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