基于Vue组件化的日期联动选择器
栏目: JavaScript · 发布时间: 6年前
内容简介:我们的社区前端工程用的是element组件库,后台管理系统用的是iview,组件库都很棒,但是日期、时间选择器没有那种“ 年份 - 月份 -天数 ” 联动选择的组件。虽然两个组件库给出的相关组件也很棒,但是有时候确实不是太好用,不太明白为什么很多组件库都抛弃了日期联动选择。因此考虑自己动手做一个。注意: 上述代码在IE10下(至少包括IE10)是没法或得到标准时间value的,因为 2018-9-2 并不是标准的日期格式(标准的是 2018-09-02),而至少 chrome 内核为我们做了容错处理(估计
我们的社区前端工程用的是element组件库,后台管理系统用的是iview,组件库都很棒,但是日期、时间选择器没有那种“ 年份 - 月份 -天数 ” 联动选择的组件。虽然两个组件库给出的相关组件也很棒,但是有时候确实不是太好用,不太明白为什么很多组件库都抛弃了日期联动选择。因此考虑自己动手做一个。
将时间戳转换成日期格式
// timestamp 为时间戳 new Date(timestamp) //获取到时间标砖对象,如:Sun Sep 02 2018 00:00:00 GMT+0800 (中国标准时间) /* 获取年: new Date(timestamp).getFullYear() 获取月: new Date(timestamp).getMonth() + 1 获取日: new Date(timestamp).getDate() 获取星期几: new Date(timestamp).getDay() */ 复制代码
将日期格式(yyyy-mm-dd)转换成时间戳
//三种形式 new Date('2018-9-2').getTime() new Date('2018-9-2').valueOf() Date.parse(new Date('2018-9-2')) 复制代码
IE下的兼容问题
注意: 上述代码在IE10下(至少包括IE10)是没法或得到标准时间value的,因为 2018-9-2 并不是标准的日期格式(标准的是 2018-09-02),而至少 chrome 内核为我们做了容错处理(估计火狐也兼容)。因此,必须得做严格的日期字符串整合操作,万不可偷懒
基于Vue组件化的日期联机选择器
该日期选择组件要达到的目的如下:
(1) 当前填入的日期不论完整或缺省,都要向父组件传值(缺省传''),因为父组件要根据获取的日期值做相关处理(如限制提交等操作等);
(2) 具体天数要做自适应,即大月31天、小月30天、2月平年28天、闰年29天;
(3) 如先选择天数为31号(或30号),再选择月数,如当前选择月数不含已选天数,则清空天数;
(4) 如父组件有时间戳传入,则要将时间显示出来供组件修改。
实现代码(使用的是基于Vue + element组件库)
<template> <div class="date-pickers"> <el-select class="year select" v-model="currentDate.year" @change='judgeDay' placeholder="年"> <el-option v-for="item in years" :key="item" :label="item" :value="item"> </el-option> </el-select> <el-select class="month select" v-model="currentDate.month" @change='judgeDay' placeholder="月"> <el-option v-for="item in months" :key="item" :label="String(item).length==1?String('0'+item):String(item)" :value="item"> </el-option> </el-select> <el-select class="day select" :class="{'error':hasError}" v-model="currentDate.day" placeholder="日"> <el-option v-for="item in days" :key="item" :label="String(item).length==1?String('0'+item):String(item)" :value="item"> </el-option> </el-select> </div> </template> <script> export default { props: { sourceDate: { type: [String, Number] } }, name: "date-pickers", data() { return { currentDate: { year: "", month: "", day: "" }, maxYear: new Date().getFullYear(), minYear: 1910, years: [], months: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], normalMaxDays: 31, days: [], hasError: false }; }, watch: { sourceDate() { if (this.sourceDate) { this.currentDate = this.timestampToTime(this.sourceDate); } }, normalMaxDays() { this.getFullDays(); if (this.currentDate.year && this.currentDate.day > this.normalMaxDays) { this.currentDate.day = ""; } }, currentDate: { handler(newValue, oldValue) { this.judgeDay(); if (newValue.year && newValue.month && newValue.day) { this.hasError = false; } else { this.hasError = true; } this.emitDate(); }, deep: true } }, created() { this.getFullYears(); this.getFullDays(); }, methods: { emitDate() { let timestamp; //暂默认传给父组件时间戳形式 if ( this.currentDate.year && this.currentDate.month && this.currentDate.day) { let month = this.currentDate.month < 10 ? ('0'+ this.currentDate.month):this.currentDate.month; let day = this.currentDate.day < 10 ? ('0'+ this.currentDate.day):this.currentDate.day; let dateStr = this.currentDate.year + "-" + month + "-" + day; timestamp = new Date(dateStr).getTime(); } else { timestamp = ""; } this.$emit("dateSelected", timestamp); }, timestampToTime(timestamp) { let dateObject = {}; if (typeof timestamp == "number") { dateObject.year = new Date(timestamp).getFullYear(); dateObject.month = new Date(timestamp).getMonth() + 1; dateObject.day = new Date(timestamp).getDate(); return dateObject; } }, getFullYears() { for (let i = this.minYear; i <= this.maxYear; i++) { this.years.push(i); } }, getFullDays() { this.days = []; for (let i = 1; i <= this.normalMaxDays; i++) { this.days.push(i); } }, judgeDay() { if ([4, 6, 9, 11].indexOf(this.currentDate.month) !== -1) { this.normalMaxDays = 30; //小月30天 if (this.currentDate.day && this.currentDate.day == 31) { this.currentDate.day = ""; } } else if (this.currentDate.month == 2) { if (this.currentDate.year) { if ( (this.currentDate.year % 4 == 0 && this.currentDate.year % 100 != 0) || this.currentDate.year % 400 == 0 ) { this.normalMaxDays = 29; //闰年2月29天 } else { this.normalMaxDays = 28; //闰年平年28天 } } else { this.normalMaxDays = 28;//闰年平年28天 } } else { this.normalMaxDays = 31;//大月31天 } } } }; </script> <style lang="less"> .date-pickers { .select { margin-right: 10px; width: 80px; text-align: center; } .year { width: 100px; } .error { .el-input__inner { border: 1px solid #f1403c; border-radius: 4px; } } } </style> 复制代码
代码解析
默认天数(normalMaxDays)为31天,最小年份1910,最大年份为当前年(因为我的业务场景是填写生日,大家这些都可以自己调)并在created 钩子中先初始化年份和天数。
监听当前日期(currentDate)
核心是监听每一次日期的改变,并修正normalMaxDays,这里对currentDate进行深监听,同时发送到父组件,监听过程:
watch: { currentDate: { handler(newValue, oldValue) { this.judgeDay(); //更新当前天数 this.emitDate(); //发送结果至父组件或其他地方 }, deep: true } } 复制代码
judgeDay方法:
judgeDay() { if ([4, 6, 9, 11].indexOf(this.currentDate.month) !== -1) { this.normalMaxDays = 30; //小月30天 if (this.currentDate.day && this.currentDate.day == 31) { this.currentDate.day = ""; } } else if (this.currentDate.month == 2) { if (this.currentDate.year) { if ( (this.currentDate.year % 4 == 0 && this.currentDate.year % 100 != 0) || this.currentDate.year % 400 == 0 ) { this.normalMaxDays = 29; //闰年2月29天 } else { this.normalMaxDays = 28; //平年2月28天 } } else { this.normalMaxDays = 28; //平年2月28天 } } else { this.normalMaxDays = 31; //大月31天 } } 复制代码
最开始的时候我用的 includes判断当前月是否是小月:
if([4, 6, 9, 11].includes(this.currentDate.month)) 复制代码
也是缺乏经验,最后测出来includes 在IE10不支持,因此改用普通的indexOf()。
emitDate:
emitDate() { let timestamp; //暂默认传给父组件时间戳形式 if ( this.currentDate.year && this.currentDate.month && this.currentDate.day) { let month = this.currentDate.month < 10 ? ('0'+ this.currentDate.month):this.currentDate.month; let day = this.currentDate.day < 10 ? ('0'+ this.currentDate.day):this.currentDate.day; let dateStr = this.currentDate.year + "-" + month + "-" + day; timestamp = new Date(dateStr).getTime(); } else { timestamp = ""; } this.$emit("dateSelected", timestamp);//发送给父组件相关结果 }, 复制代码
这里需要注意的,最开始并没有做上述标准日期格式处理,因为chrome做了适当容错,但是在IE10就不行了,所以最好要做这种处理。
normalMaxDays改变后必须重新获取天数,并依情况清空当前选择天数:
watch: { normalMaxDays() { this.getFullDays(); if (this.currentDate.year && this.currentDate.day > this.normalMaxDays) { this.currentDate.day = ""; } } } 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Beginning Apache Struts
Arnold Doray / Apress / 2006-02-20 / USD 44.99
Beginning Apache Struts will provide you a working knowledge of Apache Struts 1.2. This book is ideal for you Java programmers who have some JSP familiarity, but little or no prior experience with Ser......一起来看看 《Beginning Apache Struts》 这本书的介绍吧!