<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在日常工作中,比不可少會用到時間元件,我們的第一反應就是直接到元件庫去找一下現成的來用下,畢竟,時間元件看起來還是很複雜的,對於沒接觸過的人來說,要自己去寫一個這樣的元件出來,還是有難度的,但是作為一名前端開發,這麼常見的元件,我們還是值得取自己寫一個這樣的元件的,現在就手把手帶你實現vue中的DatePicker元件。看完不會找我。
在開始寫程式碼之前,建議代價先看看時間元件的佈局,目前主流的元件庫iview ,element等提供的時間元件佈局都基本類似,功能也差不多,因此在這裡實現的元件庫的佈局也也element家的佈局差不多,大家先看下佈局的最終樣子。 這是日的時間元件,當我們這個能實現的時候,像那些年,月的就更簡單了,因此這裡我們只實現一個,其他的可以自己擴充套件。
/** * @Description 獲取當前月份的天數 * @param { Array } 年月組成的陣列,例如:[2022,7] * @return {Number}例如:2022年7月有31天 返回31 **/ export function getCurrentMonthCount([year, month]) { // 當我們範例化Date函數的時候,傳入第三個引數為0可以通過getDate獲取到當前月份具體有多少天 return new Date(year, month, 0).getDate(); } /** * @Description 獲取當前月份1號是星期二幾 * @param { Array } 年月組成的陣列,例如:[2022,7] * @return {Number} 例如2022-7-1是星期5,返回5 **/ export function getFirstMonthDayWeek([year, month]) { return new Date(year, month - 1, 1).getDay(); } /** * @Description 根據年月,組裝渲染天的表格資料 * @param { Array } 年月組成的陣列,例如:[2022,7] * @return {Array} **/ /* 在這裡介紹下我們時間元件寫法的思路: 1.對於時間元件的佈局,可以先去參考iview element等開源元件庫的date-picker元件的佈局,基本上都是一樣的 2.在清楚佈局之後,我們需要根據使用者傳入的時間,生成一個6*7=42的天數的td單元格,在這42個單元格中,包含上月剩餘的天數,當前月份的全部天數,下月的開始天數 3.如果你清楚了步驟二,那麼我們接下來就容易多了,我們要計算上月的天數,當前月份的全部天數,下月的開始天數,以及當前月份1號星期幾 4.由於頭部是星期日,星期一,星期二,星期三,星期四,星期五,星期六的佈局,因此我們需要計算當前月份1號星期幾,這樣我們就能找到上月的剩餘天數了,下月的剩餘天數就等於42-當前月份天數-上月剩餘天數 5.在上面步驟知道後我們就可以著手根據上面提供的工具函數,生成我們需要的表格資料了 最終生成的是6*7的二維陣列,因為表格天數的佈局為6*7的佈局,資料格式如下: 陣列的個數代表了渲染的列數,內部每項陣列代表每列的td個數 [ [ { //代表當前的td幾號 value: xxx, //上個月的號數和下個月的號數標識下,渲染的時候,我們樣式另外佈局 disbled: true, //當前td的時間格式,用於點選了,給input顯示以及供使用者使用格式為2022-7-22 date: xxx, // 當前天的時間td,我們需要高亮顯示。新增標識 active:xxx, //當前td的索引 index: xxx, }, {}, {}, {}, {}, {}, {} ], [], [], [], [], [], ] */ export function genarateDayData([year, month]) { // 獲取上月天數 let lastMonthCount = getCurrentMonthCount([year, month - 1]); // 獲取當月天數 let currentMonthCount = getCurrentMonthCount([year, month]); // 獲取當月1號星期 let currentMonthFirstDayWeek = getFirstMonthDayWeek([year, month]); let dayList = []; let lastMonthPointer = 1; let currentMonthPoiner = 1; let nextMonthPointer = 1; // 根據日期元件的天數佈局,共計42天,包含上月剩餘天數+當月天數+下月初始天數 for (let i = 0; i < 42; i++) { // 上個月需要渲染的td個數,以及對應的值 if (lastMonthPointer <= currentMonthFirstDayWeek) { // 上月 dayList.unshift({ value: lastMonthCount--, disbled: true, date: year + "-" + (month - 1) + "-" + (lastMonthCount + 1), index: i, }); lastMonthPointer++; } else if (currentMonthPoiner <= currentMonthCount) { // 當月 dayList.push({ value: currentMonthPoiner++, disbled: false, active: new Date().getFullYear() == year && new Date().getMonth() + 1 == month && currentMonthPoiner - 1 == new Date().getDate(), date: year + "-" + month + "-" + (currentMonthPoiner - 1), index: i, }); } else { // 下月 dayList.push({ value: nextMonthPointer++, disbled: true, date: year + "-" + (month + 1) + "-" + (nextMonthPointer - 1), index: i, }); } } // 當前天數高亮 // 最後將資料生成二維陣列返回:對應的就是6*7的二維陣列用於渲染天數表格列 let result = []; let index = 1; let i = 0; while (index <= 6) { let arr = []; for (let j = 0; j < 7; j++) { arr.push(dayList[i]); i++; } result.push(arr); index++; } return result; }
//用於儲存組建的常數,靜態資料,比如表頭的星期 export const weekList = ["日", "一", "二", "三", "四", "五", "六"];
<template> <div class="date-picker-wrap"> <div class="date-eidtor"> <!-- 顯示時間的input --> <input type="text" :placeholder="placeholder" class="date-edit-input" v-model="currentDate" @click.stop="showDatePannel = !showDatePannel" /> </div> <!-- 麵包通過過渡元件包裹,實現顯示隱藏友好過渡 --> <transition name="date-picker"> <div class="date-pocker-panel" v-show="showDatePannel"> <!-- 時間控制元件的頭部,使用者切換年月 --> <date-picker-head @dateRangeChange="dateRangeChange" :date="curDate" ></date-picker-head> <!-- 主要的時間顯示列表元件,用於顯示對應月份的時間 --> <date-table :list="list" @dateChange="dateChange"></date-table> </div> </transition> </div> </template> <script> import { genarateDayData } from "./utils"; import DatePickerHead from "./DatePickerHead.vue"; import DateTable from "./DateTable.vue"; export default { components: { DatePickerHead, DateTable, }, props: { // 輸入框提示 placeholder: { type: String, default: "選擇時間", }, // 時間,為Date型別,預設為當前時間 date: { type: Date, default() { return new Date(); }, }, }, data() { return { // 用於控制麵包顯示與隱藏 showDatePannel: false, // 表格資料 list: [], // 處理props時間為陣列格式[年,月] curDate: [this.date.getFullYear(), this.date.getMonth() + 1], // 使用者input顯示時間 currentDate: "", }; }, mounted() { // 獲取當前月份的時間資料 this.getDateList(); // 除開時間元件的其他地方點選,關閉時間面板 window.addEventListener("click", () => { this.showDatePannel = false; }); }, methods: { // 監聽每個td時間項點選 dateChange(date) { this.$emit("dateChange", date); this.showDatePannel = false; this.currentDate = date; }, // 頭部年月切換 dateRangeChange(type) { switch (type) { // 上一年點選 case "lastYear": this.curDate = [this.curDate[0] - 1, this.curDate[1]]; break; // 上一月點選(月份<1,就要返回到上一年的12月份) case "lastMonth": this.curDate = [ this.curDate[1] - 1 <= 0 ? this.curDate[0] - 1 : this.curDate[0], this.curDate[1] - 1 <= 0 ? 12 : this.curDate[1] - 1, ]; break; // 下一年點選 case "nextYear": this.curDate = [this.curDate[0] + 1, this.curDate[1]]; break; case "nextMonth": // 下一月點選(月份>12,就要到下一年的一月份) this.curDate = [ this.curDate[1] + 1 > 12 ? this.curDate[0] + 1 : this.curDate[0], this.curDate[1] + 1 > 12 ? 1 : this.curDate[1] + 1, ]; break; } this.getDateList(); }, // 通過props傳遞的時間,組裝成長度為42的陣列,具體看utils檔案下下面的這個方法 getDateList() { this.list = genarateDayData(this.curDate); }, }, }; </script> <style lang="less"> .date-picker-wrap { position: relative; .date-pocker-panel { position: absolute; left: 0; top: 50px; width: 324px; height: 343px; color: #606266; border: 1px solid #e4e7ed; box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); background: #fff; border-radius: 4px; line-height: 30px; padding: 12px; text-align: center; } .date-eidtor { width: 220px; .date-edit-input { background-color: #fff; background-image: none; border-radius: 4px; border: 1px solid #dcdfe6; box-sizing: border-box; color: #606266; display: inline-block; font-size: inherit; height: 40px; line-height: 40px; outline: none; padding: 0 15px; transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); width: 100%; } } .date-picker-enter-active, .date-picker-leave-active { transition: all 0.25s ease; } .date-picker-enter, .date-picker-leave-to { opacity: 0; height: 0; } } </style>
<template> <!-- 頂部的時間切換元件 --> <div class="date-picker-head"> <div class="arrow-left"> <!-- 上一年點選 --> <span class="last-year arrow" @click.stop="toogleDate('lastYear')"></span> <!-- 上一月點選 --> <span class="last-month arrow" @click.stop="toogleDate('lastMonth')"></span> </div> <!-- 顯示當前的年和月 --> <div class="date-content">{{ date[0] + "年" + date[1] + "月" }}</div> <div class="arrow-right"> <!-- 下一月點選 --> <span class="next-month arrow" @click.stop="toogleDate('nextMonth')"></span> <!-- 下一年點選 --> <span class="next-year arrow" @click.stop="toogleDate('nextYear')"></span> </div> </div> </template> <script> export default { props: { // 時間 date: { type: Array, default() { return [new Date().getFullYear(), new Date().getMonth() + 1]; }, }, }, methods: { // 派發table事件處理邏輯,引數為當前td的時間,格式為2022-7-22 toogleDate(type) { this.$emit("dateRangeChange", type); }, }, }; </script> <style lang="less"> .date-picker-head { display: flex; justify-content: space-between; margin-bottom: 12px; .last-year, .next-month { margin-right: 15px; } .arrow { cursor: pointer; } } </style>
<template> <div class="date-table"> <!-- 時間表格 --> <table> <!-- 頂部的星期元件 --> <date-picker-week-bar></date-picker-week-bar> <!-- 下方的6*7的月份天陣列件 --> <date-picker-day-content :list="list" @dateChange="dateChange" ></date-picker-day-content> </table> </div> </template> <script> import DatePickerWeekBar from "./DatePickerWeekBar.vue"; import DatePickerDayContent from "./DatePickerDayContent.vue"; export default { props: { // 表格資料 list: { type: Array, default() { return []; }, }, }, components: { DatePickerWeekBar, DatePickerDayContent, }, methods: { // 派發td天數點選事件,引數為當前天數的時間格式為 2022-07-22 dateChange(date) { this.$emit("dateChange", date); }, }, }; </script> <style lang="less"> .date-table { font-size: 12px; } </style>
<template> <thead class="date-picker-week-bar"> <tr> <th v-for="item in weekList" :key="item">{{ item }}</th> </tr> </thead> </template> <script> import { weekList } from "./constant.js"; export default { data() { return { weekList, }; }, }; </script> <style lang="less"> .date-picker-week-bar { th { width: 42px; height: 42px; color: #606266; font-weight: 400; border-bottom: 1px solid #ebeef5; } } </style>
表格主題內容元件,用於渲染具體日期
<template> <tbody class="date-picker-day-content"> <tr v-for="(item, index) in list" :key="index"> <td v-for="(subItem, index) in item" :key="index" :class="[ subItem.disbled ? 'disble-item' : 'day-item', subItem.active ? 'active' : '', subItem.index == currentDay ? 'active-click' : '', ]" @click="handleDayClick(subItem)" > {{ subItem.value }} </td> </tr> </tbody> </template> <script> export default { props: { //表格資料 list: { type: Array, default() { return []; }, }, }, data() { return { //當前點選項活躍高亮 currentDay: -1, }; }, methods: { // 處理天的表格點選,觸發關閉時間控制元件面板,設定時間input的值 handleDayClick(item) { if (item.currentDay == item.index) return; this.currentDay = item.index; this.$emit("dateChange", item.date); }, }, }; </script> <style lang="less"> .date-picker-day-content { td { width: 40px; height: 40px; color: #606266; font-weight: 400; text-align: center; cursor: pointer; } .disble-item { cursor: not-allowed; color: #c0c4cc; } .day-item.active { color: #008c8c; font-weight: bold; } .day-item.active-click { border-radius: 50%; width: 30px; height: 30px; line-height: 30px; color: #fff; background-color: #008c8c; } } </style>
import DatePicker from "./DatePicker.vue"; export { DatePicker };
<template> <div id="app"> <div class="test-date-picker"> <date-picker :date="date" @dateChange="dateChange"></date-picker> </div> </div> </template> <script> import { DatePicker } from "./components/DatePicker/index"; export default { name: "App", components: { DatePicker, }, data() { return { date: new Date(), }; }, }; </script> <style lang="less"> html, body, #app { height: 100%; width: 100%; } #app { .test-date-picker { width: 50%; margin: 20px auto; } } </style>
元件庫很多看著很難的元件,只要我們認真斟酌,然後試著去是實現下,還是不難的,實現上面的這種型別的元件之後,其他的年和月型別的就更簡答了,大家可以自己擴充套件,更多關於vue時間元件DatePicker元件的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45