您好,登錄后才能下訂單哦!
本篇內容介紹了“Vue如何實現移動端日歷”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
先看看UI給的設計圖和,需求是有數據的日期做標記,可以查看某一周/某一月的數據,周數據不用自定義,就按照日歷上的周數據截取.
實現效果
1.規劃dom部分區塊劃分
2.頁面實現
選擇月份和選擇年份與日期做了條件渲染,切換方式是點擊頂部時間切換選項
<template> <div class="calendar"> <div class="date-top"> <div class="left" @click="dateOperate('down')"> <div></div> </div> <div class="time" @click="selectDate">{{ date.join("/") }}</div> <div class="right" @click="dateOperate('up')"> <div></div> </div> </div> <!-- 日期列表 --> <div class="date-list" v-if="show === 'date'"> <div class="date-content"> <!-- 日歷頭 --> <div v-for="item in header" :key="item"> {{ item }} </div> <!-- 日列表 --> <div v-for="(s, k) in dayList" :class="[ 'date-item', s.month !== date[1] ? 'other-day' : '', s.day === date[2] && s.month === date[1] ? 'today' : '', ]" :key="s + '-' + k" @click="selectDay(s)" > {{ s.day }} <div :class="[ 'check', haveList.includes(`${s.year}-${s.month}-${s.day}`) ? 'have' : '', ]" ></div> </div> </div> <!-- 操作欄 --> <div class="date-btn"> <div class="btn-item" v-for="k in weeks + 1" :key="k" @click="weekReport(k)" > {{ k === 1 ? "" : "看周報" }} </div> </div> </div> <!-- 月份列表 --> <div class="month-list" v-else-if="show === 'month'"> <div :class="date[1] == i ? 'month-item active' : 'month-item'" v-for="i in 12" :key="i" @click="selectMonth(i)" > {{ i }}月 </div> </div> <!-- 年份列表 --> <div class="year-list" v-else @touchmove="touchMove" @touchstart="touchStart" > <div :class="date[0] === i ? 'month-item active' : 'month-item'" v-for="i in yearList" :key="i" @click="selectYear(i)" > {{ i }} </div> </div> <!-- 底部操作欄 --> <div class="date-bottom"> <div class="b-left"> <div class="tab"></div> <div class="totip">代表有睡眠報告</div> </div> <div class="b-right"> <div class="cancel" @click="cancel">取消</div> <div class="m-report" @click="changeReport">看月報</div> </div> </div> </div> </template>
css部分
<style lang="scss" scoped> .calendar { width: 100%; background-color: #fff; .date-top { width: 100%; padding: 20px; display: flex; justify-content: space-around; align-items: center; .left, .right { width: 100px; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; div { width: 20px; height: 20px; background-color: #00b7ae; } } .left > div { clip-path: polygon(0% 50%, 100% 0%, 100% 100%); } .right > div { clip-path: polygon(0% 0%, 100% 50%, 0% 100%); } .time { font-size: 38px; font-weight: 500; color: #333333; } } .date-list, .year-list, .month-list { width: 100%; padding: 30px; height: 540px; } .month-list, .year-list { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: auto; .month-item { text-align: center; display: flex; justify-content: center; align-items: center; font-size: 30px; height: 122px; } .month-item:active { background-color: #eee; } .active { background-color: #dcf4f3; } } .date-list { padding-top: 0; display: flex; .date-content { flex: 1; height: 100%; display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr; grid-template-rows: auto; grid-gap: 20px 20px; div { height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; border-radius: 10px; } .other-day { color: rgba($color: #363636, $alpha: 0.6) !important; } .today { background-color: #dcf4f3; } .date-item { font-size: 28px; font-weight: 400; color: #363636; .check { width: 10px; height: 10px; margin-top: 6px; border-radius: 50%; background-color: #00b7ae; opacity: 0; } .have { opacity: 1; } } } .date-btn { height: 100%; width: 80px; font-size: 22px; color: #4eb9f5; display: grid; grid-template-columns: 1fr; grid-template-rows: auto; grid-gap: 20px 20px; margin-left: 20px; .btn-item { display: flex; justify-content: center; align-items: center; height: 100%; } } } .date-bottom { width: calc(100% - 80px); display: flex; justify-content: space-between; align-content: center; padding: 20px; margin: 0 auto; border-top: 1px solid #eee; .b-left, .b-right { display: flex; align-items: center; } .b-left { .tab { width: 27px; height: 26px; background: #dcf4f3; border-radius: 13px; } .totip { font-size: 24px; font-weight: 400; color: #363636; margin-left: 20px; } } .b-right { .cancel { font-size: 26px; font-weight: 500; color: rgba($color: #000000, $alpha: 0.5); } .m-report { width: 195px; line-height: 70px; color: #fff; font-size: 26px; background: linear-gradient(196deg, #50dcdc, #18b6b7); border-radius: 20px; margin-left: 50px; text-align: center; } } } } </style>
3.接下來是邏輯處理部分 日數據的顯示一共42條數據,先獲取當前月的總天數,將每個月的天數保存在一個數組里,然后根據傳入的參數返回相應的天數, 因為有閏年的存在,2月會是29天,所以做了閏年的判斷.然后獲取每周的第一天是周幾,使用new Date().getDay()獲取某一天是周幾,返回的是0-7,這里為了方便使用將日歷表頭用數組保存起來返回的數字剛好是日里頭對應的下標,然后根據第一天是周幾計算出需要補上個月的幾天數據,通過new Date(y,m,0)可以獲取到上個月最后一天的,然后向日數據中添加上個月最后幾天的數據,補充下個月開始的幾天數據,直接使用42減去當月的天數和補充的上個月的天數得到的就是需要補充的下月天數.
月數據的切換顯示,前后翻動切換年數據,每年固定都是12月所以就直接寫固定值12然后v-for遍歷生成dom
年數據的切換顯示,每頁顯示12條數據,保存每頁數據的第一條和最后一條用于前后翻頁計算顯示的數據+12或者-12.
校驗選擇的月份和已選擇的日期是否匹配,因為選擇日期后再切換月份有可能切換到的月份沒有選擇的日期如31日30日29日,所以需要驗證是否正確,若是沒有的話就當前月的最后一天.
手勢操作沒有寫完整,只寫了年份選擇的滑動事件邏輯.
為了方便js部分的代碼每行都有寫詳細的注釋
自定月選擇日期范圍只需要修改日期點擊事件的邏輯,新增一個參數判斷是單日期選擇還是選擇一個日期范圍,在事件處理里面記錄點擊的兩個日期并計算中間的日期保存返回.
import { formatTime } from "@/utils/format"; export default { name: "calendar", props: { haveList: { type: Array, default: [], }, }, data() { return { // 切換日期選擇 show: "date", // 日歷頭 header: ["日", "一", "二", "三", "四", "五", "六"], // 選擇日期 date: [], // 年列表 yearList: [], // 天列表 dayList: [], // 定時器 timer: null, // 手勢操作數據 move: { pageX: 0, fNum: null, lNum: null, }, // 第一天是周幾 weeks: 0, }; }, created() {}, mounted() { let time = new Date(); this.date.push( time.getFullYear(), formatTime(time.getMonth() + 1), formatTime(time.getDate()) ); this.countDay(); }, methods: { // 計算顯示的天數據 countDay() { console.log("chufa"); let [y, m, d] = this.date; // 獲取第一天是周幾 let week = new Date(`${y}/${m}/1`).getDay(), // 獲取當前月的上個月多少天 lastDays = this.getDays(y, m - 1), // 獲取這個月有多少天 days = this.getDays(y, m); // 計算這個月有多少周 this.weeks = Math.ceil((days - (7 - week)) / 7) + 1; // 將當前月份的天數生成數組 this.dayList = Array.from({ length: this.getDays(y, m) }, (v, k) => { return { day: formatTime(k + 1), month: m, year: y, }; }); // 將本月1日前的數據補齊 for (let i = lastDays; i > lastDays - week; i--) { this.dayList.unshift({ day: i, // 如果當前日期是1月補齊的是去年12月的數據 month: +m - 1 === 0 ? 12 : formatTime(+m - 1), year: +m - 1 === 0 ? y - 1 : y, }); } // 計算需要補齊多少天 let length = this.weeks * 7 - this.dayList.length; console.log("length", week, lastDays, days, this.weeks); // 將本月最后一天的數據補齊 for (let i = 1; i <= length; i++) { this.dayList.push({ day: i, // 如果當前日期是12月補齊的是明年年1月的數據 month: +m + 1 > 12 ? 1 : formatTime(+m + 1), year: +m + 1 > 12 ? y + 1 : y, }); } console.log(this.dayList); }, // 頂部時間點擊事件 selectDate() { let type = { month: "year", date: "month", }; // 判斷點擊事件選擇月份還是年份 if (this.show !== "year") { this.show = type[this.show]; } // 如果是月份就計算dateList數據 if (this.show === "month") { // 清空每頁顯示的年份數據 this.yearList.length = 0; // 計算頁面顯示的年份數據 每頁顯示12條數據 for (let i = this.date[0] - 4; i <= this.date[0] + 7; i++) { this.yearList.push(i); } } }, // 屏幕點擊事件 touchStart(val) { // 獲取按下屏幕的x軸坐標 this.move.pageX = val.touches[0].pageX; }, // 左右滑動切換事件 touchMove(val) { // 獲取按下屏幕移動結束的x軸坐標 let move = val.touches[0].pageX; clearTimeout(this.timer); // 判斷往左滑動還是往右滑動 // 滑動結束x軸坐標減去最初按下坐標為負數就是往左滑動,翻看當前日期以后的年份 if (move - this.move.pageX < -20) { console.log("右滑", this.move.lNum); // 定時器防抖 this.timer = setTimeout(this.changeYear("right"), 100); } // 滑動結束x軸坐標減去最初按下坐標為正數就是往右滑動,翻看當前日期以前的年份 if (move - this.move.pageX > 20) { // 定時器防抖 this.timer = setTimeout(this.changeYear("left"), 100); } }, // 年份選擇切換 changeYear(type) { // 清空每頁顯示的年份數據 this.yearList.length = 0; if (type === "right") { // 計算頁面顯示的年份數據 每頁顯示12條數據 for (let i = this.move.lNum + 1; i < this.move.lNum + 13; i++) { this.yearList.push(i); } } else { for (let i = this.move.fNum - 12; i < this.move.fNum; i++) { this.yearList.push(i); } } }, // 年份點擊事件 selectYear(val) { this.date[0] = val; this.show = "month"; }, // 月份點擊事件 selectMonth(val) { this.date[1] = val; this.show = "date"; this.countDay(); this.checkDay(); }, // 校驗選擇的月份和已選擇的日期是否匹配 checkDay() { // 獲取選擇的年月有多少天 防止這年不是閏年 就將日期跳轉到28號,或者有的月份沒有31號就跳到30號 let num = this.getDays(this.date[0], this.date[1]); if (num < this.date[2]) { this.date.splice(2, 1, num); } }, // 日期點擊事件 selectDay(val) { let oVal = this.date[1]; this.date.splice(1, 2, val.month, val.day); if (val.month !== oVal) { this.countDay(); } this.$emit("change", this.date.join("-")); }, // 獲取某個月有多少天 getDays(year, month) { // 一年中每個月的天數 let days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; // 判斷是不是閏年 2月29天 if (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) { days[1] = 29; } return days[month - 1]; }, //左右按鈕點擊事件 dateOperate(type) { let [y, m, d] = this.date; // 如果是向后翻 if (type === "up") { // 日期向后翻 切換月份 if (this.show === "date") { if (+m === 12) { this.date.splice(0, 1, y + 1); this.date.splice(1, 1, "01"); } else { this.date.splice(1, 1, formatTime(+m + 1)); } // 月份向后翻 切換年份 } else if (this.show === "month") { this.date.splice(0, 1, y + 1); // 年份向后翻 重組數據 } else { this.changeYear("right"); } // 如果是前后翻 } else { // 日期向前翻 切換月份 if (this.show === "date") { if (+m === 1) { this.date.splice(0, 1, y - 1); this.date.splice(1, 1, 12); } else { this.date.splice(1, 1, formatTime(+m - 1)); } // 月份向前翻 切換年份 } else if (this.show === "month") { this.date.splice(0, 1, y - 1); // 年份向前翻 重組數據 } else { this.changeYear("left"); } } this.countDay(); this.checkDay(); }, // 右側按鈕點擊事件 weekReport(i) { if (i === 1) return; let arr = [], // 選擇一周的數據 開始 s = 7 * (i - 1) - 7, // 結束 e = 7 * (i - 1); // 遍歷日數據 截取選擇的周數據 for (let k = s; k < e; k++) { arr.push( `${this.dayList[k].year}-${this.dayList[k].month}-${this.dayList[k].day}` ); } this.$emit("weekReport", arr); }, // 看月報事件 changeReport() { let [y, m, d] = this.date; this.$emit("changeReport", `${y}-${m}`); }, // 取消事件 cancel() { this.$emit("cancel"); }, }, computed: {}, watch: { yearList(nVal, oVal) { // 記錄每一頁顯示的數據第一位和最后一位 用于計算下一頁或者上一頁的數據 this.move.fNum = nVal[0]; this.move.lNum = nVal[11]; }, deep: true, immediate: true, }, };
formatTime是給月份和日期小于10的前面加0的方法
“Vue如何實現移動端日歷”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。