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(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>
    
  • 效果图

posted @ 2022-11-23 17:25  不完美的完美  阅读(99)  评论(0编辑  收藏  举报