如何使用vue编写一个简单的日历组件
直接先把我的代码贴上
1.CSS
* {margin: 0;padding: 0;list-style: none;font-size: 16px;}#calendar {width: 50%;margin: 120px auto;padding: 10px;/* background: #ccc; */border-radius: 5px;overflow: hidden;background: #28a1ff;}.month {background: #28a1ff;color: #fff;height: 32px;margin: 0 auto;padding: 0 10px;}.month ul {margin: 0 auto;height: 32px;width: 90%;display: flex;align-items: center;justify-content: space-between;}.month ul li {cursor: pointer;}.arrow {width: 32px;text-align: center;}.weekdays,.days {display: grid;grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;align-items: center;justify-items: center;padding: 10px 10px;}.weekdays {grid-template-rows: 32px;background: #28a1ff;color: #fff;}.days {grid-template-rows: 32px 32px 32px 32px 32px;background-color: #0986e7;color: #fff;padding-top: 10px;border-radius: 5px;}.days li {width: 100%;height: 100%;display: flex;align-items: center;justify-items: center;}.days li span {width: 100%;height: 100%;text-align: center;line-height: 32px;}.other-month {color: #ccc;}.active {background: #28a1ff;border-radius: 5px;}.this-month:hover {cursor: pointer;background: #28a1ff;border-radius: 5px;}.year-container,.month-container {background: #fff;padding: 10px;border-radius: 5px;display: grid;grid-template-columns: 1fr 1fr 1fr;grid-gap: 5px;width: 240px;position: fixed;}.year-container span,.month-container span {text-align: center;cursor: pointer;}.year-container span:hover,.month-container span:hover {color: #28a1ff;}.isYear,.isMonth {color: #28a1ff;}
2.HTML
<div id="calendar" ref="calendar"><!-- 年份 月份 --><div class="month"><ul><!--点击会触发pickpre函数,重新刷新当前日期 @click(vue v-on:click缩写) --><li class="arrow" @click="pickPre(currentYear,currentMonth)">❮</li><li class="year-month"><span class="choose-year"@click="pickYear(currentYear,currentMonth,1,$event)">{{ currentYear }}年</span><span class="choose-month"@click="pickYear(currentYear,currentMonth,2,$event)">{{ currentMonth }}月</span><span>{{currentDay}}日</span></li><li class="arrow" @click="pickNext(currentYear,currentMonth)">❯</li></ul></div><!-- 星期 --><ul class="weekdays"><li>一</li><li>二</li><li>三</li><li>四</li><li>五</li><li>六</li><li>日</li></ul><!-- 日期 --><ul class="days"><!-- 核心 v-for循环 每一次循环用<li>标签创建一天 --><li v-for="dayobject in days" @click="changeDay(dayobject)" :key="dayobject.id":class="[{'other-month':!dayobject.isThisMonth},{'active':dayobject.isThisDay},{'this-month':dayobject.isThisMonth}]"><span>{{ dayobject.day.getDate() }}</span></li></ul><div class="year-container" ref="container" v-if="showYearList"><span v-for="(item,index) in yearList" :class="item==currentYear?'isYear':''" @click="selectYear(item)">{{item}}</span></div><div class="month-container" ref="container" v-if="showMonth"><span v-for="(item,index) in month" :class="item==currentMonth?'isMonth':''" @click="selectMonth(item)">{{item}}</span></div></div>
3.Script
var myVue = new Vue({el: '#calendar',data: {currentDay: new Date().getDate(),currentMonth: new Date().getMonth() + 1,currentYear: new Date().getFullYear(),currentWeek: 1,days: [],yearList: [],showYearList: false,month: null,showMonth: false},created: function () {//在vue初始化时调用var d = new Date()this.initData(this.formatDate(d.getFullYear(), d.getMonth() + 1, d.getDate()));},mounted() {this.isApp()},methods: {initData: function (cur) {this.days = []; //数据初始化var date = new Date(cur);this.currentDay = date.getDate();this.currentYear = date.getFullYear();this.currentMonth = date.getMonth() + 1;this.currentWeek = date.getDay(); // 1...6,0if (this.currentWeek == 0) this.currentWeek = 7; // 今天是周日,放在第一行第7个位置,前面6个var thisMonthDays = new Date(this.currentYear, this.currentMonth, 0).getDate() //当月总天数var thisMonthFirstDayIsWeeks = new Date(this.currentYear, this.currentMonth - 1, 1).getDay() == 0 ? 7 : new Date(this.currentYear, this.currentMonth - 1, 1).getDay() //当月第一天是周几,周日是0var thisMonthLastDayIsWeeks = new Date(this.currentYear, this.currentMonth - 1,thisMonthDays).getDay() == 0 ? 7 : new Date(this.currentYear, this.currentMonth - 1, thisMonthDays).getDay() //当月最后一天是周几// console.log("thisMonthDays:",thisMonthDays,";","thisMonthFirstDayIsWeeks:",thisMonthFirstDayIsWeeks,";","thisMonthLastDayIsWeeks:",thisMonthLastDayIsWeeks,";")//上一个月if (thisMonthFirstDayIsWeeks != 1) {//当月的第一天不是周一,需要补全前面的(上一个月的)天数var y = this.currentMonth == 1 ? this.currentYear - 1 : this.currentYearvar m = this.currentMonth == 1 ? 12 : this.currentMonth - 1var d = new Date(y, m, 0).getDate() //上一个月总天数for (let i = 0; i < thisMonthFirstDayIsWeeks - 1; i++) {//判断上一个月是不是前一个年的最后一个月var newD = new Date(y, m - 1, d - (thisMonthFirstDayIsWeeks - (i + 2)))var dayobject = {};dayobject.day = newD;dayobject.isThisMonth = falsedayobject.isThisDay = falsethis.days.push(dayobject);}}//当前月for (var i = 0; i < thisMonthDays; i++) {var newD = new Date(this.currentYear, this.currentMonth - 1, i + 1)var dayobject = {};dayobject.day = newD;dayobject.isThisMonth = truedayobject.isThisDay = i + 1 == this.currentDaythis.days.push(dayobject);}//下一个月if (thisMonthLastDayIsWeeks != 7) {for (let i = 0; i < 7 - thisMonthLastDayIsWeeks; i++) {//判断下一个月是不是下一年的第一个月var newD = new Date(this.currentMonth == 11 ? this.currentYear + 1 : this.currentYear, this.currentMonth == 11 ? 0 : this.currentMonth, i + 1)var dayobject = {};dayobject.day = newD;dayobject.isThisMonth = falsedayobject.isThisDay = falsethis.days.push(dayobject);}}},pickPre: function (year, month) {// setDate(0); 上月最后一天// setDate(-1); 上月倒数第二天// setDate(dx) 参数dx为 上月最后一天的前后dx天if (month == 1) {month = 12year = year - 1} else {month = month - 1}this.initData(this.formatDate(year, month, 1));},pickNext: function (year, month) {if (month == 12) {month = 1year = year + 1} else {month = month + 1}this.initData(this.formatDate(year, month, 1));},pickYear: function (year, month, type, e) {var top = e.y + 32,left = e.x - 120;this.showMonth = falsethis.showYearList = falseif (type == 1) {this.yearList.length = 9for (let i = 0; i < this.yearList.length; i++) {if (i < 4) {this.yearList[i] = year - (4 - i)} else {this.yearList[i] = year + (i - 4)}}this.showYearList = true} else {this.showMonth = truethis.month = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]}this.$nextTick(function () {this.$refs.container.style = `top:${top}px;left:${left}px;`})},// 返回 类似 -01-02 格式的字符串formatDate: function (year, month, day) {var y = year;var m = month;if (m < 10) m = "0" + m;var d = day;if (d < 10) d = "0" + d;var data = y + "-" + m + "-" + dreturn data},changeDay(dayobject) {const dayDetail = dayobject.dayreturn dayDetail},selectYear(item){this.showYearList = falsethis.currentYear = itemthis.initData(this.formatDate(this.currentYear,this.currentMonth,this.currentDay))},selectMonth(item){this.showMonth = falsethis.currentMonth = itemthis.initData(this.formatDate(this.currentYear,this.currentMonth,this.currentDay))},isApp() {// console.log(window.navigator)if (window.navigator.userAgent.includes("Mobile")) {this.$refs.calendar.style.width = "90%"}}},});
功能包括选择年份和月份
年份是当前年份前后各四个年份
因为这个是我日常写的东西没有在Vue项目中去使用,把这个迁移到Vue项目做为组件。
功能难点主要是当月的前一个月的日期和后一个月的日期的显示。在代码initDate()方法中实现
CSS方面使用grid布局和flex布局比较灵活。
仅供大家参考。
欢迎大家指点。