【10分钟系列】手把手带你封装一个简易日历组件

597 阅读3分钟

基于Element UI,封装一个简易日历组件。日历默认显示当前年月日,用户指定不同的年、月时,日历自动更新 simple.jpg

核心思路

根据用户指定的年月,自动更新视图

第一步:移除Calendar组件中不需要的部分

  1. 移除Calendar组件自带的头部,给父级盒子添加样式穿透,并给日历盒子的头部设定:.el-calendar__header { display: none; }

第二步:引入Select组件

  1. 添加年、月的下拉选择组件。年份以当前年为中心,分别向前、向后推5年,2017-2026作为年的可选择区间;月份写死。
  2. 将年份和月份与el-calendar的依赖数据关联,利用v-model实现自动更新视图 核心代码:
    // 年选择框
    <span>年:</span>
    <el-select
        v-model="chosenYear"
        size="mini"
        style="width: 120px"
        @change="changeHandler"
     >
         <el-option
             v-for="item in yearOptions"
             :key="item"
             :label="item"
             :value="item"
          />
     </el-select>
     
     // 月选择框
     <span>月:</span>
     <el-select
         v-model="chosenMonth"
         size="mini"
         style="width: 120px"
         @change="changeHandler"
      >
          <el-option 
              v-for="item in 12" 
              :key="item" 
              :label="item" 
              :value="item" />
      </el-select>
     

第三步:使用插槽和业务实现

  1. 自定义日历单元格的内容。必须使用组件指定的具名插槽dateCell;函数调用getDay提取日期中的多少号
  2. 为周末添加 “ 休 ” 标识。isWeek函数调用的结果,结合v-if实现动态添加 “ 休 ” 标识
  3. 12个月可写死,年份采用动态的。计算属性yearOptions实现前后5年的年份区间选择
  4. 年份选择和月份选择公用一个事件处理函数changeHandler,两种共同作用于el-calendar的依赖数据

结构

<el-calendar v-model="currentDate">
 <template v-slot:dateCell="scope">
     <div class="date-content">
         <!-- 1. 将每个单元格中的时间转换为当月的几“ 号 ” -->
         <span class="text"> {{ getDay(scope.date) }}</span>
         <!-- 2. 添加休息日的文字“ 休 ” ,要根据插槽的时间决定是否显示 “ 休 ”-->
         <span v-if="isWeek(scope.date)" class="rest"></span>
     </div>
  </template>
</el-calendar>

行为

<script>
export default {
  name: 'Calender',
  data() {
    return {
      currentDate: new Date(),
      // 1. 当前下拉选择框所选中的年份, 默认是当前年份
      chosenYear: new Date().getFullYear(),
      // 2. 年份下拉选择框的选项依赖数组,迁移到计算属性中
      // 3.下拉选择框所选中的月份, 默认是当前月份
      chosenMonth: new Date().getMonth() + 1
      // getMonth返回一个0 到 11的整数值: 0 代表一月份,1 代表二月份, 2 代表三月份,依次类推
    }
  },

  computed: {
    // 年份下拉选择框的选项依赖数组,在小范围区间内动态变化
    yearOptions() {
      // 1. 获取当前年份
      const currentYear = this.currentDate.getFullYear()
      // new一个能容纳10个成员的数组(相当于是个类数组),并以undefined充当占位标识填充这10个空位,方便后续遍历数组时对成员重新赋值
      // 2. 准备数组
      const arr = Array.from(new Array(10))
      // 3. 遍历替换每个成员
      arr.forEach((item, index) => {
        // 以当前年为中心,向前5年,向后5年,再结合索引号,则数组成员的值为:数组成员 = 当前年 -5 + 索引号
        // 替换空数组中替换成员
        arr[index] = currentYear - 5 + index
      })
      return arr
    }
  },
  
  methods: {
    // 粗略的日期转换,简单转为当月的几号
        getDay(origin) {
          const date = new Date(origin)
          // getDate()方法返回一个指定的日期对象为一个月中的哪一日(从1--31)
          const num = date.getDate()
          return num
        },

    // 根据是否为周六周日,来决定是否显示文字“ 休 ”
        isWeek(origin) {
          const date = new Date(origin)
          // getDay()方法根据指定的日期对象,返回一个具体日期中一周的第几天(number型),0 表示星期天
          const day = date.getDay()
          if (day === 0 || day === 6) {
            return true
          } else {
            return false
          }
        },

        changeHandler() {
          // 将当前的年份 或 月份作为实际参数传给Date()函数,然后覆盖currentDate变量中的日期,就能实现日历组件根据指定年份 或 月份更新页面
          this.currentDate = new Date(`${this.chosenYear}-${this.chosenMonth}`)
          // currentDate 作为el-calendar的依赖数据,值可以是时间对象/字符串/数字
        }
      }
}
</script>