基于Vue组件化的日期联动选择器功能的实现代码


Posted in Javascript onNovember 30, 2018

我们的社区前端工程用的是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 = "";
  }
 }
}

最终效果

基于Vue组件化的日期联动选择器功能的实现代码

基于Vue组件化的日期联动选择器功能的实现代码

总结

以上所述是小编给大家介绍的基于Vue组件化的日期联动选择器功能的实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript 星级评分效果(手写)
Dec 24 Javascript
jquery实现图片等比例缩放以及max-width在ie中不兼容解决
Mar 21 Javascript
jQuery.Validate验证库的使用介绍
Apr 26 Javascript
bootstrap模态框垂直居中效果
Dec 03 Javascript
基于jquery实现的鼠标悬停提示案例
Dec 11 Javascript
vue日期组件 支持vue1.0和2.0
Jan 09 Javascript
JS中的Replace()传入函数时的用法详解
Sep 11 Javascript
深入理解Vue2.x的虚拟DOM diff原理
Sep 27 Javascript
JavaScript中Require调用js的实例分享
Oct 27 Javascript
Vue-cli@3.0 插件系统简析
Sep 05 Javascript
微信小程序云开发之新手环境配置
May 16 Javascript
微信小程序如何实现在线客服功能
Oct 16 Javascript
vue拖拽排序插件vuedraggable使用方法详解
Aug 21 #Javascript
JS实现图片拖拽交换效果
Nov 30 #Javascript
Vue+Webpack完美整合富文本编辑器TinyMce的方法
Nov 30 #Javascript
jQuery实现网页拼图游戏
Apr 22 #jQuery
vue 双向数据绑定的实现学习之监听器的实现方法
Nov 30 #Javascript
基于jquery实现九宫格拼图小游戏
Nov 30 #jQuery
微信小程序canvas.drawImage完全显示图片问题的解决
Nov 30 #Javascript
You might like
php字符串截取函数用法分析
2014/11/25 PHP
浅谈socket同步和异步、阻塞和非阻塞、I/O模型
2016/12/15 PHP
PHP生成腾讯云COS接口需要的请求签名
2018/05/20 PHP
通过上下左右键和回车键切换光标实现代码
2013/03/08 Javascript
基于jQuery实现下拉框
2014/11/24 Javascript
JavaScript变量声明详解
2014/11/27 Javascript
kindeditor编辑器点中图片滚动条往上顶的bug
2015/07/05 Javascript
基于JavaScript实现生成名片、链接等二维码
2015/09/20 Javascript
React创建组件的三种方式及其区别
2017/01/12 Javascript
vue+swiper实现组件化开发的实例代码
2017/10/26 Javascript
详解vue+vuex+koa2开发环境搭建及示例开发
2018/01/22 Javascript
layui之select的option叠加问题的解决方法
2018/03/08 Javascript
JavaScript事件冒泡与事件捕获实例分析
2018/08/01 Javascript
vue.js父子组件通信动态绑定的实例
2018/09/28 Javascript
在Vue项目中取消ESLint代码检测的步骤讲解
2019/01/27 Javascript
vue3.0中使用postcss-pxtorem的具体方法
2019/11/20 Javascript
原生js无缝轮播插件使用详解
2020/03/09 Javascript
js实现验证码功能
2020/07/24 Javascript
Nuxt的路由配置和参数传递方式
2020/11/06 Javascript
[02:21]十步杀一人,千里不留行——DOTA2全新英雄天涯墨客展示
2018/08/29 DOTA
Python中字典(dict)合并的四种方法总结
2017/08/10 Python
selenium+python自动化测试之鼠标和键盘事件
2019/01/23 Python
python实现小球弹跳效果
2019/05/10 Python
python实现的config文件读写功能示例
2019/09/24 Python
Python Numpy 控制台完全输出ndarray的实现
2020/02/19 Python
jupyter notebook指定启动目录的方法
2021/03/02 Python
IE浏览器单独写CSS样式的几种方法
2014/10/14 HTML / CSS
精选鞋类、服装和配饰的全球领先目的地:Bodega
2021/02/27 全球购物
社会保险接收函
2014/01/12 职场文书
家长写给孩子的评语
2014/04/18 职场文书
捐款活动总结
2014/08/27 职场文书
红色电影观后感
2015/06/18 职场文书
高中诗歌鉴赏教学反思
2016/02/16 职场文书
2016年幼儿园教师师德承诺书
2016/03/25 职场文书
golang实现一个简单的websocket聊天室功能
2021/10/05 Golang
Python Pandas解析读写 CSV 文件
2022/04/11 Python