在日常工作中需要填写日期的时候,会用到日期选择器,来方便的进行日、月、年的选择。这里我们会用Vue来实现一个日期选择器,效果如下:
实现功能:日期选择弹出层
选择天面板
选择月面版
选择年面版
支持用户输入
CSS样式美化
组件的使用方式很简单,只需要传入对应的日期对象value即可:
export default {
name: 'DatePicker',
data () {
return {
value: undefined
};
},
};
下面就开始一步步实现组件吧 !
日期选择弹出层
当用户点击输入框时,会弹出日期选择面板。在组件内部,会通过visible来控制弹出层的显示隐藏:
class="go-date-picker-input"
@focus="visible=true"
prefix="calendar"
placeholder="请选择时间"
>
export default {
name: 'GoDatePicker',
props: {
value: {
type: Date,
default: () => new Date()
}
},
data () {
return {
visible: false,
};
},
mounted () {
document.body.addEventListener('click', this.onClickBody);
},
beforeDestroy () {
document.body.removeEventListener('click', this.onClickBody);
},
methods: {
onClickBody (e) { // Vue内部会自动帮我们修改this指向 const { picker} = this.$refs;
// 过滤掉弹出层和日期选择器内的元素 if (picker.contains(e.target)) {
return;
}
this.visible = false;
},
}
};
当输入框激活时,显示弹出层,当点击外部区域时,会隐藏弹出层。需要注意的是当点击date-picker内部,弹出层并不会隐藏。
Node.contains(otherNode)可以用来判断otherNode是否是Node的后代节点(包括Node本身),返回Boolean。这里我们通过这个api来判断点击的元素e.target是否在date-picker内部,如果是的话不会隐藏弹出层,可以让用户在date-picker中进行相应的操作。
展示天面板
当用户点击输入框后,首先弹出的是天面板,面板头部会显示当前的年月信息。面板主体有 6 行,会分别包括上月、当前月、下月的天数:
显示头部信息
我们会对传入的value进行拷贝,在内部通过tempValue来进行保存,并且监听value的变化,保证tempValue可以获取到value的最新值。当我们在内部切换日期面板而没有选中某个日期时,就不会更新value,而只是更新内部的tempValue属性:
export default {
name: 'GoDatePicker',
props: {
value: {
type: Date,
default: () => new Date()
}
},
components: { PickerDays, PickerMonths, PickerYears },
data () {
return {
visible: false,
mode: 'picker-days',
tempValue: cloneDate(this.value),
};
},
computed: {
formatDate () {
const [year, month, day] = getYearMonthDay(this.tempValue);
return { year, month: month + 1, day };
},
},
watch: {
value (val) {
this.tempValue = cloneDate(val);
}
},
// some code ...};
formatDate计算属性会通过tempValue计算出当前的年、月、日,方便展示。
显示内容区域
内容区域的展示会复杂很多,实现的思路如下:获取当前月第一天是星期几,推导出前一个月展示的天数
获取当月的展示总天数
总共要展示的天数为 42,减去前一个月和当前月展示的天数即为下个月展示的天数
export default {
name: 'PickerDays',
data () {
return {
weeks: ['一', '二', '三', '