vue 实现日历看板
- vue + elementUI + moment
-
根据切换月份查看当月的日历
-
main.ts
import Vue from "vue"; import App from "./App.vue"; import router from "./router"; import store from "./store"; import moment from "moment"; import ElementUI from "element-ui"; import "element-ui/lib/theme-chalk/index.css"; Vue.prototype.$moment = moment; Vue.prototype.$moment.locale("zh-cn"); Vue.use(ElementUI); Vue.config.productionTip = false; new Vue({ router, store, render: h => h(App), }).$mount("#app");
-
vue.d.ts
// 1. 确保在声明补充的类型之前导入 'vue' import Vue, { ComponentOptions } from "vue"; import echarts from "echarts"; // 引入echarts // 2. 定制一个文件,设置你想要补充的类型 // 在 types/vue.d.ts 里 Vue 有构造函数类型 declare module "vue/types/vue" { // 3. 声明为 Vue 补充的东西 interface Vue { $moment: any; } }
-
效果图
-
calendar.vue
<template> <div class="calendar"> <common-date type="month" @change="onChangeDate" v-model="formObj.month"></common-date> <div class="calendar-box"> <div class="calendar-box-top"> <div>日</div> <div>一</div> <div>二</div> <div>三</div> <div>四</div> <div>五</div> <div>六</div> </div> <div class="calendar-box-content"> <div v-for="(item,i) in week" :key="i + 100" class="calendar-box-content-box"> </div> <div v-for="(item,index) in monthCalendar" :key="index" class="calendar-box-content-box"> <div class="calendar-title"> {{ item.day }} </div> </div> <div v-for="(item,i) in endWeek" :key="i + 200" class="calendar-box-content-box"> </div> </div> </div> <div class="calendar-box"> <div class="calendar-box-top"> <div>日</div> <div>一</div> <div>二</div> <div>三</div> <div>四</div> <div>五</div> <div>六</div> </div> <div class="calendar-box-content"> <div v-for="(item,i) in lastMonthList" :key="i + 100" class="calendar-box-content-box"> <div class="calendar-seconed"> {{ item.day }} </div> </div> <div v-for="(item,index) in monthCalendar" :key="index" class="calendar-box-content-box"> <div class="calendar-title"> {{ item.day }} </div> </div> <div v-for="(item,i) in nextMonthList" :key="i + 200" class="calendar-box-content-box"> <div class="calendar-seconed"> {{ item.day }} </div> </div> </div> </div> </div> </template> <script lang="ts"> import { Component, Vue } from "vue-property-decorator"; import commonDate from "./commonDate.vue"; @Component({ name: "", components: { commonDate, }, }) export default class extends Vue { formObj = { month: "", }; week = 0; endWeek = 0; monthCalendar: any = []; // 月历看板 lastMonthList = []; // 上月日历 nextMonthList: any = []; // 下月日历 created() { this.formObj.month = this.$moment(new Date()).format("YYYY-MM"); this.onChangeDate(); console.log(this.$moment("19961128", "YYYYMMDD").fromNow()); } onChangeDate() { // 获取月份 // const month = this.formObj.month // ? this.$moment(this.formObj.month).format("M") // : ""; // const year = this.formObj.month // ? this.$moment(this.formObj.month).format("YYYY") // : ""; const month = this.$moment(this.formObj.month).format("M") || ""; const year = this.$moment(this.formObj.month).format("YYYY") || ""; // 获取月份的天数 const days = this.$moment(this.formObj.month).daysInMonth(); this.monthCalendar = days; const arr = Array.from(new Array(days)).map((e, i) => ({ allDay: year + "-" + month + "-" + (i + 1), year: Number(year), month: Number(month), day: i + 1, })); this.monthCalendar = arr; // 获取本月的第一天是周几 设置星期几,其中星期日为 0、星期六为 6 // 月初 const startDay = this.$moment(this.formObj.month) .startOf("month") .format("YYYY-MM-DD"); // 月末 const endDay = this.$moment(this.formObj.month) .endOf("month") .format("YYYY-MM-DD"); this.week = this.$moment(startDay).day(); const lastAdd = this.$moment(this.formObj.month).add(-1, "months"); const lastYear = lastAdd.format("YYYY"); // 上年 const lastMonth = lastAdd.format("M"); // 上月 const nextAdd = this.$moment(this.formObj.month).add(1, "months"); const nextYear = nextAdd.format("YYYY"); // 下年 const nextMonth = nextAdd.format("M"); // 下月 // 上个月的日历数据 const lastArr = Array.from(new Array(this.week)).map((el, index) => { if (index === 0) { return { allDay: this.$moment(this.formObj.month) .date(index) .format("YYYY-M-D"), year: Number( this.$moment(this.formObj.month).date(index).format("YYYY") ), month: Number( this.$moment(this.formObj.month).date(index).format("M") ), day: Number(this.$moment(this.formObj.month).date(index).format("D")), }; } else { return { allDay: this.$moment(this.formObj.month) .date(-index) .format("YYYY-M-D"), year: Number( this.$moment(this.formObj.month).date(-index).format("YYYY") ), month: Number( this.$moment(this.formObj.month).date(-index).format("M") ), day: Number( this.$moment(this.formObj.month).date(-index).format("D") ), }; } }); this.lastMonthList = this.sortKey(lastArr, "allDay"); this.endWeek = 6 - this.$moment(endDay).day(); const nextArr = Array.from(new Array(this.endWeek)).map((el, index) => ({ allDay: this.$moment(this.formObj.month) .add(1, "months") .date(index + 1) .format("YYYY-M-D"), year: Number( this.$moment(this.formObj.month) .add(1, "months") .date(index + 1) .format("YYYY") ), month: Number( this.$moment(this.formObj.month) .add(1, "months") .date(index + 1) .format("M") ), day: Number( this.$moment(this.formObj.month) .add(1, "months") .date(index + 1) .format("D") ), })); this.nextMonthList = nextArr; } sortKey(array: any, key: any) { return array.sort(function (a: any, b: any) { const x = a[key]; const y = b[key]; const end = x > y ? 1 : 0; return x < y ? -1 : end; }); } } </script> <style lang="scss" scoped> .calendar { width: 100%; .calendar-box { width: 100%; border: 1px solid #ebeef5; flex-direction: column; display: flex; margin-bottom: 10px; .calendar-box-top { width: 100%; display: flex; text-align: center; border-bottom: 1px solid #ebeef5; > div { width: calc(100% / 7); font-size: 14px; padding: 12px 0; color: #606266; font-weight: 400; border-right: 1px solid #ebeef5; } } .calendar-box-content { display: flex; flex-wrap: wrap; height: 100%; .calendar-box-content-box { width: calc(100% / 7); border-bottom: 1px solid #ebeef5; border-right: 1px solid #ebeef5; padding: 8px; box-sizing: border-box; cursor: pointer; min-height: 60px; .calendar-title { color: #303133; } .calendar-seconed { color: #999; } } } } } </style>
-
commonDate.vue
<template> <!-- 年月日 --> <el-date-picker clearable :default-time="type === 'datetime' ? '12:00:00' : ''" :disabled="disabled ? true : false" :format="valueType" :picker-options="pickerBeginDateBefore" placeholder="选择日期" :type="type" :value-format="valueType" @change="$emit('change', val)" @clear="$emit('change', val)" v-model="val"> </el-date-picker> </template> <script lang="ts"> import { Component, Vue, Model, Watch, Prop } from "vue-property-decorator"; @Component({ name: "MyPost", components: {} }) export default class extends Vue { @Model("change") value; val = null; @Prop({ type: Boolean, required: false, default: false }) disabled; // 是否禁用 @Prop({ type: String, required: false, default: "" }) startDate; // 开始时间 @Prop({ type: String, required: false, default: "" }) endDate; // 结束时间 @Prop({ type: String, required: true, default: "date" }) type; // 日期类型 @Watch("value", { immediate: true }) onChangeValue(value) { this.val = value; } created() { this.val = this.value; } valueType = "yyyy-MM-dd"; // 日期格式 @Watch("type", { immediate: true }) getFormat(val) { if (val === "date") { // 年月日 this.valueType = "yyyy-MM-dd"; } else if (val === "datetime") { // 年月日时分秒 this.valueType = "yyyy-MM-dd HH:mm"; } else if (val === "month") { // 年月 this.valueType = "yyyy-MM"; } else if (val === "year") { // 年 this.valueType = "yyyy"; } } pickerBeginDateBefore = { disabledDate: time => { const endDateVal = this.endDate; const beginDateVal = this.startDate; if (beginDateVal && endDateVal) { const tmpTime = time.getTime() > new Date(endDateVal).getTime() || time.getTime() < new Date(beginDateVal).getTime() - 86400000; return tmpTime; } if (endDateVal) { return time.getTime() > new Date(endDateVal).getTime(); } if (beginDateVal) { return time.getTime() < new Date(beginDateVal).getTime() - 86400000; } }, }; } </script> <style lang="scss" scoped> </style>
-
效果图
<template> <div class="calendar"> <common-date type="month" @change="onChangeDate" v-model="formObj.month"></common-date> <div class="calendar-box"> <div class="calendar-box-top"> <div>一</div> <div>二</div> <div>三</div> <div>四</div> <div>五</div> <div>六</div> <div>日</div> </div> <div class="calendar-box-content"> <div v-for="(item,i) in lastMonthList" :key="i + 100" class="calendar-box-content-box"> <div class="calendar-seconed"> {{ item.day }} </div> </div> <div v-for="(item,index) in monthCalendar" :key="index" class="calendar-box-content-box"> <div class="calendar-title"> {{ item.day }} </div> </div> <div v-for="(item,i) in nextMonthList" :key="i + 200" class="calendar-box-content-box"> <div class="calendar-seconed"> {{ item.day }} </div> </div> </div> </div> </div> </template> <script lang="ts"> import { Component, Vue } from "vue-property-decorator"; import commonDate from "./commonDate.vue"; @Component({ name: "", components: { commonDate, }, }) export default class extends Vue { formObj = { month: "", }; week = 0; endWeek = 0; monthCalendar: any = []; // 月历看板 lastMonthList = []; // 上月日历 nextMonthList: any = []; // 下月日历 created() { this.formObj.month = this.$moment(new Date()).format("YYYY-MM"); this.onChangeDate(); } onChangeDate() { const month = this.$moment(this.formObj.month).format("M") || ""; const year = this.$moment(this.formObj.month).format("YYYY") || ""; // 获取月份的天数 const days = this.$moment(this.formObj.month).daysInMonth(); this.monthCalendar = days; const arr = Array.from(new Array(days)).map((e, i) => ({ allDay: year + "-" + month + "-" + (i + 1), year: Number(year), month: Number(month), day: i + 1, })); this.monthCalendar = arr; // 获取本月的第一天是周几 设置星期几,其中星期日为 0、星期六为 6 // 月初 const startDay = this.$moment(this.formObj.month) .startOf("month") .format("YYYY-MM-DD"); // 月末 const endDay = this.$moment(this.formObj.month) .endOf("month") .format("YYYY-MM-DD"); this.week = this.$moment(startDay).day(); const newWeek = this.week ? this.week - 1 : 6; // 上个月的日历数据 const lastArr = Array.from(new Array(newWeek)).map((el, index) => { if (index === 0) { return { allDay: this.$moment(this.formObj.month) .date(index) .format("YYYY-M-D"), year: Number( this.$moment(this.formObj.month).date(index).format("YYYY") ), month: Number( this.$moment(this.formObj.month).date(index).format("M") ), day: Number(this.$moment(this.formObj.month).date(index).format("D")), }; } else { return { allDay: this.$moment(this.formObj.month) .date(-index) .format("YYYY-M-D"), year: Number( this.$moment(this.formObj.month).date(-index).format("YYYY") ), month: Number( this.$moment(this.formObj.month).date(-index).format("M") ), day: Number( this.$moment(this.formObj.month).date(-index).format("D") ), }; } }); this.lastMonthList = this.sortKey(lastArr, "allDay"); this.endWeek = 7 - this.$moment(endDay).day(); const nextArr = Array.from(new Array(this.endWeek)).map((el, index) => ({ allDay: this.$moment(this.formObj.month) .add(1, "months") .date(index + 1) .format("YYYY-M-D"), year: Number( this.$moment(this.formObj.month) .add(1, "months") .date(index + 1) .format("YYYY") ), month: Number( this.$moment(this.formObj.month) .add(1, "months") .date(index + 1) .format("M") ), day: Number( this.$moment(this.formObj.month) .add(1, "months") .date(index + 1) .format("D") ), })); this.nextMonthList = nextArr; } sortKey(array: any, key: any) { return array.sort(function (a: any, b: any) { const x = a[key]; const y = b[key]; const end = x > y ? 1 : 0; return x < y ? -1 : end; }); } } </script> <style lang="scss" scoped> .calendar { width: 100%; .calendar-box { width: 100%; border: 1px solid #ebeef5; flex-direction: column; display: flex; margin-bottom: 10px; .calendar-box-top { width: 100%; display: flex; text-align: center; border-bottom: 1px solid #ebeef5; > div { width: calc(100% / 7); font-size: 14px; padding: 12px 0; color: #606266; font-weight: 400; border-right: 1px solid #ebeef5; } } .calendar-box-content { display: flex; flex-wrap: wrap; height: 100%; .calendar-box-content-box { width: calc(100% / 7); border-bottom: 1px solid #ebeef5; border-right: 1px solid #ebeef5; padding: 8px; box-sizing: border-box; cursor: pointer; min-height: 60px; .calendar-title { color: #303133; } .calendar-seconed { color: #999; } } } } } </style>