日历组件

日历组件在平时我的项目中是十分常见的一个组件,那么咱们就来实现一下。实现之前要晓得有哪几个须要留神的点。
-一、日期要怎么显示?
每个月须要展现不同的日期,那么咱们就来找找法则吧。
1.每个月须要展现固定的42天。
2.每个月的一号是周几,比方上图中的一号是周二,那么咱们能够应用工夫的getDay函数获取一号的是2,而后让第一天往前推2天,就是咱们须要展现在日历上的第一天了。

  • 二、日期框里的年月不能依据输入框里的日期变动,因为前面还会波及到切换问题
  • 三、每次切换都要更新日历板中的日期,使其与对应月份展现的雷同
  • 四、每次点击日历中的日期须要暗藏日历板(点击切换年月按钮不暗藏)
  • 五、点击日历板上的日期之后再次点击输入框会展现对应月份对应工夫,对应工夫须要给一个非凡展现(如上图蓝色局部)
  • 六、不是当月的工夫须要和以后月的日期有辨别(色彩辨别)
  • 七、选中了某一天须要更新父组件中的数据
  • 八、输入框中录入年月日,点击enter键,再次点击input会弹出对应的日期并且标蓝色

下面就是封装这个日历所须要留神到的点,那么上面看代码吧;

代码实现

父组件
<template>  <div id="datePicker">    <Calendar :time="time" v-model="time"></Calendar>    <div style="display: inline-block">{{time}}</div>  </div></template><script>  import Calendar from '../components/calendar';  export default {    name: 'datePicker',    components: {      Calendar    },    data() {      return {        time: new Date()      };    },    methods: {}  };</script><style></style>

子组件

<template>  <div id="calendar" v-click-outside>    <input type="text" ref="input" class="input" :value="formatterTime" @focus="handlClick" @keydown="enterInput">    <div class="content" v-if="isShow">      <div class="title">        <div class="oper">          <span class="iconfont icon-shuangjiantouzuo" @click="handlChangeDate('year',-1)"></span>          <span class="iconfont icon-zuojiantou" @click="handlChangeDate('month',-1)"></span>        </div>        <div class="date">{{`${timeCopy.year}年${timeCopy.month}月`}}</div>        <div class="oper">          <span class="iconfont icon-youjiantou" @click="handlChangeDate('month',+1)"></span>          <span class="iconfont icon-shuangjiantouyou" @click="handlChangeDate('year',+1)"></span>        </div>      </div>      <div class="week">        <span class="week-item" v-for="(v,i) in weekList" :key="i">{{v}}</span>      </div>      <ul class="days">        <li class="days-row" v-for="(v,i) in 6" :key="i">              <span class="days-item" v-for="(vs,j) in 7" :key="j"                    @click="chooseDay(getCurrentMonthDays[i*7+j])"                    :class="[                    {'gray-day':getCurrentMonthDays[i*7+j].getMonth()+1!=timeCopy.month},                    {'high-light':getCurrentMonthDays[i*7+j].getDate()==timeCopy.day}                    ]"              >                {{getCurrentMonthDays[i*7+j].getDate()}}              </span>        </li>      </ul>    </div>  </div></template><script>  export default {    name: 'calendar',    props: {      time: {type: Date}    },    directives: {      'clickOutside': {        bind(el, builing, vNode) {          let handler = (e) => {            let input = document.getElementsByClassName('input')[0];            let title = document.getElementsByClassName('title')[0];            if (!title) return;            if (!input.contains(e.target) && !title.contains(e.target)) {              vNode.context.isShow = false;            }          };          document.addEventListener('click', handler);        }      }    },    computed: {      formatterTime() {        let {year, month, day} = this.timeCopy;        return `${year}-${month}-${day}`;      },      getCurrentMonthDays() {        let {year, month} = this.timeCopy;        let firstDay = new Date(`${year}-${month}-01`);        let week = firstDay.getDay();        let beginDay;        if (week === 0) {          beginDay = firstDay - 7 * 1000 * 60 * 60 * 24;        } else {          beginDay = firstDay - week * 1000 * 60 * 60 * 24;        }        let dateArr = [];        for (let i = 0; i < 42; i++) {          dateArr.push(new Date(beginDay + i * 1000 * 60 * 60 * 24));        }        return dateArr;      }    },    data() {      return {        isShow: false,        timeCopy: {},        weekList: ['日', '一', '二', '三', '四', '五', '六']      };    },    methods: {      enterInput(e) {        if (e.keyCode == '13') {          let val = e.srcElement.value;          let {month, day} = this.setData(new Date(val));          if (isNaN(month) || isNaN(day)) {            alert('输出不非法哦');            return;          }          this.timeCopy = this.setData(new Date(e.srcElement.value));          this.$emit('input', new Date(e.srcElement.value));          this.isShow = false;          this.$refs.input.blur();        }      },      handlChangeDate(flag, val) {        this.timeCopy[flag] += val;        if (this.timeCopy.month > 12) {          this.timeCopy.month = 1;          this.timeCopy.year += 1;        }        if (this.timeCopy.month < 1) {          this.timeCopy.month = 12;          this.timeCopy.year -= 1;        }      },      chooseDay(date) {        this.$emit('input', date);        this.timeCopy = this.setData(date);      },      setData(time) {        let year = time.getFullYear();        let month = time.getMonth() + 1;        let day = time.getDate();        return {year, month, day};      },      handlClick() {        this.isShow = true;      }    },    created() {      this.timeCopy = this.setData(this.time);    }  };</script><style lang="less" scoped>  * {    margin: 0;    padding: 0;  }  ul li {    list-style: none;  }  #calendar {    @commonColor: #00a0ff;    text-align: center;    display: inline-block;    input {      width: 268px;      background-color: #fff;      border-radius: 4px;      border: 1px solid #dcdfe6;      color: #606266;      height: 40px;      line-height: 40px;      outline: none;      padding: 0 15px;    }    .content {      user-select: none;      position: absolute;      width: 300px;      z-index: 100;      background: #fff;      color: #606266;      border: 1px solid #e4e7ed;      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);      border-radius: 4px;      line-height: 30px;      margin: 5px 0;      .title {        display: flex;        height: 25px;        line-height: 25px;        margin-bottom: 15px;        .oper {          font-size: 16px;          cursor: pointer;          flex: 1;        }        .date {          flex: 1;        }      }      .week {        display: flex;        border-bottom: 1px solid #bfc4cc;        .week-item {          flex: 1;          font-size: 14px;        }      }      .days {        display: flex;        flex-direction: column;        padding: 5px;        font-size: 12px;        justify-content: space-evenly;        .days-row {          display: flex;          .days-item {            flex: 1;            cursor: pointer;            &:hover {              color: @commonColor;            }          }        }      }    }    .gray-day {      color: #bfc4cc !important;    }    .high-light {      color: @commonColor;    }  }</style>