关于日历:实现一个简单的日历输入组件

34次阅读

共计 4541 个字符,预计需要花费 12 分钟才能阅读完成。

日历组件

日历组件在平时我的项目中是十分常见的一个组件,那么咱们就来实现一下。实现之前要晓得有哪几个须要留神的点。
- 一、日期要怎么显示?
每个月须要展现不同的日期,那么咱们就来找找法则吧。
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>

正文完
 0