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>
    
posted @ 2022-11-23 17:25  不完美的完美  阅读(117)  评论(0编辑  收藏  举报