美文网首页
日历组件

日历组件

作者: 良人不良 | 来源:发表于2019-11-25 10:47 被阅读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>

相关文章

  • 高级任务3

    轮播组件曝光加载组件Tab组件日历组件Modal 组件

  • 日历组件

    1. pc日历 http://www.my97.net/dp/demo/index.htm http://tlia...

  • 日历组件

  • 日历组件

    页面引用日历组件 数据双向绑定,监听组件得年份和月份得变化 1613692800000 2021-02-19...

  • 日历组件

    日历展现形式普通文档流弹出层 isMask 灵活控制星期的排列、星期的显示格式、月份的显示格式1月 一月 Jan...

  • 日历组件

    前言:由于业务的需求,需要一个日历组件,查阅挺多组件,发现与实际业务需求有点区别,特别是后期样式修改挺麻烦的,所以...

  • pc端个性化日历实现

    一、实现日历组件 二、个性化日历使用

  • 面向对象实战

    代码预览 tab组件懒加载组件无限轮播组件无限轮播二次封装组件modal组件日历组件

  • 面向对象实战

    teb切换曝光组件轮播组件日历选择Modal代码地址

  • 面向对象 实战 -常用JS组件

    轮播组件轮播二次封装预览 曝光加载组件预览 Tab 组件预览 日历组件预览 Modal 组件预览

网友评论

      本文标题:日历组件

      本文链接:https://www.haomeiwen.com/subject/hsddwctx.html