日历组件

2019-11-25  本文已影响0人  良人不良
<template>
  <div v-click-outside>
    <input type="text" :value="formatDate">
    <div v-if="isVisible" class="pannel">
      <div class="pannel-nav">
        <span @click="prevYear"><</span>
        <span @click="prevMonth"><<</span>
        <span>{{time.year}}年</span>
        <span>{{time.month + 1}}月</span>
        <span @click="nextMonth">>></span>
        <span @click="nextYear">></span>
      </div>
      <div class="pannel-content">
        <span v-for="(item,index) in week">{{item}}</span>
        <div class="days">
          <div v-for="i in 6" :key="i">
          <!--判断是不是当月,不是就变灰-->
            <span
                v-for="j in 7" :key="j"
                @click="handleChooseDate(visibleDays[(i-1) * 7 + (j-1)])"
                class="cell"
                :class="[
                  {notCurrerntMonth:!isCurrerntMonth(visibleDays[(i-1) * 7 + (j-1)])},
                  {today: isToday(visibleDays[(i-1) * 7 + (j-1)])},
                  {select: isSelect(visibleDays[(i-1) * 7 + (j-1)])}
                ]"
            >
              {{visibleDays[(i-1) * 7 + (j-1)].getDate()}}
            </span>
          </div>
        </div>
      </div>
      <div class="pannel-footer">
        今天
      </div>
    </div>
  </div>
</template>

<script>
  // 日历组件
  export default {
    name: 'Calendar',
    // https://www.cnblogs.com/moqiutao/p/8334780.html
    directives: {
      clickOutside: {  // 指令得生命周期
        // el: 指令所绑定的元素,可以用来直接操作DOM。
        // binding:  一个对象,包含指令的很多信息。
        // vnode: Vue编译生成的虚拟节点。
        bind(el,bindings,vnode) {   // 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
          // 把时间绑定给document上,看一下点击得是否是当前的这个元素内部
          let handler = (e) => {
            // console.log(e.target)
            if(el.contains(e.target)) {  // el.contains(e.target) 原生dom操作
              // 判断下日历面板是否已显示
              if(!vnode.context.isVisible) {
                vnode.context.hanldeFocus()
              }
            }else {
              if(vnode.context.isVisible) {
                vnode.context.handleBlur()
              }
            }
          }
          el.handler = handler
          document.addEventListener('click',handler)
        },
        unbind(el){
          document.removeEventListener('click',el.handler)
        }
      }
    },
    data () {
      let {year, month} = this.getYearMonthDay(this.value)
      return {
        week: ['日', '一', '二', '三', '四', '五', '六'],
        time: {year,month},
        isVisible: false // 控制日历面板是否可见
      }
    },
    props: {
      value: {
        type: Date,
        default: () => new Date() // 对象,数组返回的默认值必须是一个对象
      }
    },
    mounted() {
      console.log(this.visibleDays)
    },
    computed: {
      visibleDays() {
        let {year,month} = this.getYearMonthDay(this.getDate(this.time.year,this.time.month, 1))
        // 获取当前月份第一天
        let currentFirstDay = this.getDate(year,month,1)
        // 获取第一天是周几
        let week = currentFirstDay.getDay()
        console.log('week',week)
        // 计算当月开始的天数
        let startDay = currentFirstDay - week * 60 * 60 * 1000 * 24
        // 循环42天
        let arr = []
        for(let i = 0; i < 42; i++) {
          arr.push(new Date(startDay + i * 60 * 60 * 1000 * 24))
        }
        return arr
      },
      formatDate() {
        let {year,month,day} = this.getYearMonthDay(this.value)
        return `${year}-${month + 1}-${day}`
      }
    },
    methods:{
      // 获取年月日
      getYearMonthDay() {
        const year = date.getFullYear()
        const month = date.getMonth()
        const day = date.getDate()
        return {year, month, day}
      },
      getDate(year, month, day) {
        return new Date(year, month, day)
      },
      hanldeFocus() {
        this.isVisible = true // 显示面板
      },
      handleBlur() {
        this.isVisible = false // 隐藏面板
      },
      // 是否当月
      isCurrerntMonth(date) {
        // 传入值匹配当前年月
        let {year,month}  = this.getYearMonthDay(this.getDate(this.time.year,this.time.month,1))
        let {year:y, month:m} = this.getYearMonthDay(date);
        return year === y && month === m
      },
      // 是否今天
      isToday(date) {
        let {year,month,day} = this.getYearMonthDay(new Date())
        let {year:y, month:m, day:d} = this.getYearMonthDay(date)
        return year === y && month === m && day === d
      },
      // 改变input value
      handleChooseDate(date) {
        this.time = this.getYearMonthDay(date)
        this.$emit('change',date)
        this.handleBlur()  // 关闭日历模板
      },
      // 是否被选中
      isSelect(date) {
        let {year,month,day} = this.getYearMonthDay(this.value)
        let {year:y, month:m, day:d} = this.getYearMonthDay(date)
        return year === y && month === m && day === d
      },
      // 上一个月
      prevMonth() {
        let d = this.getDate(this.time.year,this.time.month,1)
        d.setMonth(d.getMonth()-1)
        this.time = this.getYearMonthDay(d)
      },
      // 下一个月
      nextMonth() {
        let d = this.getDate(this.time.year,this.time.month,1)
        d.setMonth(d.getMonth() + 1)
        this.time = this.getYearMonthDay(d)
      },
      // 上一年
      prevYear() {
        let d = this.getDate(this.time.year,this.time.month,1)
        d.setFullYear(d.getFullYear() - 1)
        this.time = this.getYearMonthDay(d)
      },
      // 下一年
      nextYear() {
        let d = this.getDate(this.time.year,this.time.month,1)
        d.setFullYear(d.getFullYear() + 1)
        this.time = this.getYearMonthDay(d)
      }
    }
  }
</script>

<style scoped lang="less">
.pannel {
  width: 32 * 7px;
  position: absolute;
  background: #fff;
  margin-top: 10px;
  box-shadow: 2px 2px 2px pink, -2px -2px 2px pink;
  .pannel-nav {
    display: flex;
    justify-content: space-around;
    height: 30px;
    user-select: none;
    span {
      cursor: pointer;
    }
  }
  .pannel-content {
    span {
      display: inline-flex;
      justify-content: center;
      align-items: center;
      width: 32px;
      height: 32px;
      font-weight: bold;
      box-sizing: border-box;
    }
    .cell {
      cursor: pointer;
    }
    .cell:hover {
      border: 1px solid pink;
    }
    .notCurrerntMonth {
      color: gray;
    }
    .today {
      background: red;
      color: white;
    }
    .select {
      background: pink;
      color: white;
    }
  }
  .pannel-footer {
    height: 30px;
    text-align: center;
  }
}
</style>
上一篇 下一篇

猜你喜欢

热点阅读