用Vue写一个datepicker的方法

jquery最重要的作用是跨浏览器,而现在浏览器市场虽不完美,但已远没有从前那么惨,数据驱动视图的思想倍受欢迎,大家开始使用前端框架取代jquery,我个人比较喜欢vue.js,所以想试着用vue.js写一个组件出来。

为了发布到npm上,所以给项目地址改名字了,但是内部代码没有改,使用方法比之前方便。

GitHub地址: Here

功能&期望

这个datepicker目前仅实现了一些常用的功能:

选择时间(这话说得有点多余)

立即学习“前端免费学习笔记(深入)”;

最大/最小时间限制

中/英文切换(其实也就星期和月份需要切换)

可以以.vue形式使用,也可在浏览器环境中直接使用

没了。。。

目录结构

万事的第一步依然是创建项目,只是单一组件,结构并不复杂,Datepicker.vue是最重要的组件文件,dist是webpack的输出文件夹,index.js是webpack打包的入口文件,最后是webpack的配置文件,用来对我们的库文件进行打包用的。因此项目结构就是这样:

.├── Datepicker.vue├── LICENSE├── README.md├── dist│ └── vue-datepicker.js├── index.js├── package.json└── webpack.config.js

登录后复制

从Datepicker.vue入手

以.vue的方式写Vue组件是一种特殊写法,每个Vue文件包括template, script, style三部分,template最好不要成为片段实例,所以最外层先套一层p,当做整个组件的根元素。一个datepicker一般由两部分组成,一个用来显示日期的input框,一个用来选择日期的panel,因为我发现input在移动端会自动唤起键盘,所以没有使用input,直接用了p模拟,通过点击事件决定panel的显隐。value是最终的结果,需要和父组件通信,所以将value写成了prop,在父组件中使用value.sync=”xxx”,datepicker的value就和父组件的xxx双向绑定了。

 

  

 

 

 

 export default {  data () {   return {    panelState: false //初始值,默认panel关闭   }  },  props: {   value: String  } }

登录后复制

渲染日期列表

一个月最少是28天,如果把周日排在开头,那么最少(1号恰好是周日)需要4行,但是每个月天数30,31居多,而且1号又不一定是周日,我索性干脆按最多的情况设计了,共6行,当月日期没填满的地方用上个月或下个月的日期补齐,这样就方便计算了,而且切换月份时候panel高度不会变化。日期列表的数组需要动态计算,Vue提供了computed这个属性,所以直接将日期列表dateList写成计算属性。我的方法是将日期列表固定为长度为42的数组,然后将本月,上个月,下个月的日期依次填充。

computed: { dateList () {  //获取当月的天数  let currentMonthLength = new Date(this.tmpMonth, this.tmpMonth + 1, 0).getDate()  //先将当月的日期塞入dateList  let dateList = Array.from({length: currentMonthLength}, (val, index) => {   return {    currentMonth: true,    value: index + 1   }  })  //获取当月1号的星期是为了确定在1号前需要插多少天  let startDay = new Date(this.year, this.tmpMonth, 1).getDay()  //确认上个月一共多少天  let previousMongthLength = new Date(this.year, this.tmpMonth, 0).getDate() } //在1号前插入上个月日期 for(let i = 0, len = startDay; i 

这里用Array.from来初始化了一个数组,传入一个Array Like,转化成数组,在拼接字符串时候采用了arr[arr.length]和[{}].concat(arr)这种方式,因为在JsTips上学到这样做性能更好,文章的最后会贴出相关链接。
这样,日期列表就构建好了,在template中使用v-for循环渲染出来



登录后复制登录后复制  

样式上就可以自己发挥了,怎么喜欢怎么写。需要注意的是循环日期可能会出现上个月或这个月的日期,我通过previuosMonth,currentMonth和nextMonth分别做了标记,对其他功能提供判断条件。
年份和月份的列表都是差不多的道理,年份列表的初始值我直接写在了data里,以当前年份为第一个,为了和月份保持一致,每次显示12个,都通过v-for渲染。

data () { return {  yearList: Array.from({length: 12}, (value, index) => new Date().getFullYear() + index) }}

登录后复制

选择日期功能

选择顺序是:年 -> 月 -> 日,所以我们可以通过一个状态变量来控制panel中显示的内容,绑定适合的函数切换显示状态。

 

  

登录后复制          

  

          

  

         

选择日期的方法就不细说了,在selectYear,selectMonth中对年份,月份变量赋值,再分别将panelType推向下一步就实现了日期选择功能。

不过在未选择完日期之前,你可能不希望当前年月的真实值发生变化,所以在这些方法中可先将选择的值赋给一个临时变量,等到seletDate的时候再一次性全部赋值。

selectMonth (month) { if(this.validateMonth(month)){  return }else{  //临时变量  this.tmpMonth = month  //切换panel状态  this.panelType = 'date' }},selectDate (date) { //validate logic above... //一次性全部赋值 this.year = tmpYear this.month = tmpMonth this.date = date.value this.value = `${this.tmpYear}-${('0' + (this.month + 1)).slice(-2)}-${('0' + this.date).slice(-2)}` //选择完日期后,panel自动隐藏 this.panelState = false}

登录后复制

最大/小时间限制

最大/小值是需要从父组件传递下来的,因此应该使用props,另外,这个值可以是字符串,也应该可以是变量(比如同时存在两个datepicker,第二个的日期不能比第一个大这种逻辑),所以应该使用Dynamically bind的方式传值。

登录后复制

增加了限制条件,对于不合法的日期,其按钮应该变为置灰状态,我用了比较时间戳的方式来判断日期是否合法,因为就算当前panel中的日期是跨年或是跨月的,通过日期构造函数创建时都会帮你转换成对应的合法值,省去很多判断的麻烦:

new Date(2015, 0, 0).getTime() === new Date(2014, 11, 31).getTime() //truenew Date(2015, 12, 0).getTime() === new Date(2016, 0, 0).getTime() //true

登录后复制

因此验证日期是否合法的函数是这样的:

validateDate (date) { let mon = this.tmpMonth if(date.previousMonth){  mon -= 1 }else if(date.nextMonth){  mon += 1 } if(new Date(this.tmpYear, mon, date.value).getTime() >= new Date(this.minYear, this.minMonth - 1, this.minDate).getTime()  && new Date(this.tmpYear, mon, date.value).getTime() 

动态计算位置

当页面右侧有足够的空间显示时,datepicker的panel会定位为相对于父元素left: 0的位置,如果没有足够的空间,则应该置于right: 0的位置,这一点可以通过Vue提供的动态样式和样式对象来实现(动态class和动态style其实只是动态props的特例),而计算位置的时刻,我放在了组件声明周期的ready周期中,因为这时组件已经插入到DOM树中,可以获取style进行动态计算:


ready () { if(this.$el.parentNode.offsetWidth + this.$el.parentNode.offsetLeft - this.$el.offsetLeft 

登录后复制

为了panel的显隐可以平滑过渡,可以使用transition做过渡动画,这里我简单地通过一个0.2秒的透明度过渡让显隐更平滑。

//less syntax.toggle{ &-transition{  transition: all ease .2s; } &-enter, &-leave{  opacity: 0; }}

登录后复制

中英文切换

这里其实也很简单,这种多语言切换实质就是一个key根据不同的type而输出不同的value,所以使用filter可以很容易的实现它!比如渲染星期的列表:


登录后复制    filters : { week (item, lang){  switch (lang) {   case ‘en’:    return {0: ‘Su’, 1: ‘Mo’, 2: ‘Tu’, 3: ‘We’, 4: ‘Th’, 5: ‘Fr’, 6: ‘Sa’}[item]   case ‘ch’:    return {0: ‘日’, 1: ‘一’, 2: ‘二’, 3: ‘三’, 4: ‘四’, 5: ‘五’, 6: ‘六’}[item]   default:    return item  } }}

多种使用方式

对于一个Vue组件,如果是使用webpack + vue-loader的.vue单文件写法,我希望这样使用:

//App.vue import datepicker from 'path/to/datepicker.vue' export default {  components: { datepicker} }

登录后复制

如果是直接在浏览器中使用,那么我希望datepicker这个组件是暴露在全局下的,可以这么使用:

//index.html     

   new Vue({ el: '#app', components: { datepicker } })  

登录后复制

这里我选择了webpack作为打包工具,使用webpack的output.library和output.linraryTarget这两个属性就可以把你的bundle文件作为库文件打包。library定义了库的名字,libraryTarget定义了你想要打包的格式,具体可以看文档。我希望自己的库可以通过datepicker加载到,并且打包成umd格式,因此我的webpack.config.js是这样的:

module.exports = { entry: './index.js', output: {  path: './dist',  library: 'datepicker',  filename: 'vue-datepicker.js',  libraryTarget: 'umd' }, module: {  loaders: [   {test: /.vue$/, loaders: ['vue']},   {test: /.js$/, exclude: /node_modules/, loaders: ['babel']}  ] }}

登录后复制

打包完成的模块就是一个umd格式的模块啦,可以在浏览器中直接使用,也可以配合require.js等模块加载器使用!

适配 Vue 2.x

Vue 2.0已经发布有段时间了,现在把之前的组件适配到Vue 2.0。迁移过程还是很顺利的,核心API改动不大,可以借助vue-migration-helper来找出废弃的API再逐步修改。这里只列举一些我需要修改的API。

filter

2.0中的filter只能在mustache绑定中使用,如果想在指令式绑定中绑定过滤后的值,可以选择计算属性。我在月份和星期的显示中使用到了过滤器来过滤语言类型,但我之前是在指令式绑定中使用的filter,所以需要如下修改,:

//修改前

//修改后,filter传参的方式也变了,变成了函数调用的风格

{{tmpMonth + 1 | month(language)}}

登录后复制

移除$index和$key

这两个属性不会在v-for中被自动创建了,如需使用,要在v-for中自行声明:


登录后复制//

ready 生命周期移除

ready从生命周期钩子中移除了,迁移方法很简单,使用mounted和this.$nextTick来替换。

prop.sync弃用

prop的sync弃用了,迁移方案是使用自定义事件,而且Datepicker这种input类型组件,可以使用表单输入组件的自定义事件作为替换方案。自定义组件也可以使用v-model指令了,但是必须满足两个条件:

接收一个value的prop

值发生变化时,触发一个input事件,传入新值。

所以Datepicker的使用方式也不是了,而是。组件自身向父级传值的方式也不一样了:

//1.x版本,设置了value的值会同步到父级this.value = `${this.tmpYear}-${('0' + (this.month + 1)).slice(-2)}-${('0' + this.date).slice(-2)}`//2.x版本,需要自己触发input事件,将新值作为参数传递回去let value = `${this.tmpYear}-${('0' + (this.month + 1)).slice(-2)}-${('0' + this.date).slice(-2)}`this.$emit('input', value)

登录后复制

相关推荐:

Vue引用datepicker插件无法监听datepicker输入框的值怎么办

jQuery UI 日期选择器Datepicker详解

详解JS控件bootstrap datepicker的使用方法(图)

以上就是用Vue写一个datepicker的方法的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2788375.html

(0)
上一篇 2025年3月8日 18:25:37
下一篇 2025年3月8日 18:25:47

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Vue引用datepicker插件无法监听datepicker输入框的值怎么办

    本文主要介绍了vue引用第三方datepicker插件无法监听datepicker输入框的值的解决,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能帮助到大家。 一、背景 在Vue项目中使用了第三方的datepicker插件,在选择…

    编程技术 2025年3月8日
    000
  • vue实现记住密码到cookie的方法

    大体思路就是通过存/取/删cookie实现的;每次进入登录页,先去读取cookie,如果浏览器的cookie中有账号信息,就自动填充到登录框中,存cookie是在登录成功之后,判断当前用户是否勾选了记住密码,如果勾选了,则把账号信息存到co…

    2025年3月8日
    200
  • 在vue-cli中使用路由的方法

    本文主要和大家介绍在vue-cli中使用路由的方法,给大家做个参考,希望能帮助大家正确在vue-cli中使用路由。 1.首先npm中是否有vue-router 一般在vue-cli的时候就已经下载好了依赖包了 2.使用vue的话正常的需要涉…

    2025年3月8日
    200
  • React事件绑定的几种方法分享

    本文主要给大家介绍了关于react学习之事件绑定的几种方法对比,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,希望能帮助大家更深掌握react事件绑定的方法。 React事件绑定 由于类的方法默认不会绑定thi…

    编程技术 2025年3月8日
    200
  • 三种JavaScript定义函数方法

    本文主要和大家介绍javascript定义函数的三种实现方法的相关资料,希望通过本文大家能够掌握三种定义函数的方法,需要的朋友可以参考下,希望能帮助到大家。 JavaScript定义函数的三种实现方法 【1】正常方法 function pr…

    编程技术 2025年3月8日
    200
  • table中两列CheckBox只能选中一个的jQuery代码

    本文主要为大家带来一篇jquery实现table中两列checkbox只能选中一个的示例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮助到大家。 //html 选项一选项二姓名小红小明 登录后复制 …

    2025年3月8日
    200
  • ES6中Object.assign()方法

    本文主要和大家分享,object.assign方法用于对象的合并,将源对象( source )的所有可枚举属性,复制到目标对象( target ),下面这篇文章主要给大家介绍了关于es6中新增的object.assign()方法的相关资料,…

    编程技术 2025年3月8日
    200
  • vue-router实现权限控制方法

    本文主要和大家介绍vue-router 权限控制的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮助到大家。 最近搭建了公司的后台管理系统, 而且系统还比较庞大, 要实现以下几点: 菜单权限, …

    编程技术 2025年3月8日
    200
  • JavaScript求最大公共子串的方法详解

    本文主要和大家介绍javascript实现求最大公共子串的方法,涉及javascript针对字符串的遍历、匹配、运算等相关操作技巧,需要的朋友可以参考下,希望能帮助到大家。 求最大公共子串,常见的做法是使用矩阵。假设有字符串:abcdefg…

    编程技术 2025年3月8日
    200
  • 限时抢购倒计时功能实现方法

    本文主要为大家带来一篇限时抢购-倒计时的完整实例(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮助到大家。 如下所示: nbsp;HTML>  团购——限时抢 还剩  function …

    2025年3月8日
    200

发表回复

登录后才能评论