您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

datepicker怎么使用

2024/5/1 13:39:04发布18次查看
这次给大家带来datepicker怎么使用,使用datepicker的注意事项有哪些,下面就是实战案例,一起来看一下。
前言
写插件是很有意思,也很锻炼人,因为这个过程中能发现许多的细节问题。在前端发展的过程中,jquery无疑是一个重要的里程碑,围绕着这个优秀项目也出现了很多优秀的插件可以直接使用,大大节省了开发者们的时间。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双向绑定了。
<template>  <p class="date-picker">   <p class="input" v-text="value" @click="panelstate = !panelstate">  </p>  <p class="date-panel" v-show="panelstate">  </p> </template> <scrip>  export default {   data () {    return {     panelstate: false //初始值,默认panel关闭    }   },   props: {    value: string   }  } </script>
渲染日期列表一个月最少是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 < len; i++){ datelist = [{previousmonth: true, value: previousmongthlength - i}].concat(datelist) } //补全剩余位置 for(let i = 0, item = 1; i < 42; i++, item++){ datelist[datelist.length] = {nextmonth: true, value: i} } return datelist }
这里用array.from来初始化了一个数组,传入一个array like,转化成数组,在拼接字符串时候采用了arr[arr.length]和[{}].concat(arr)这种方式,因为在jstips上学到这样做性能更好,文章的最后会贴出相关链接。
这样,日期列表就构建好了,在template中使用v-for循环渲染出来
<ul class="date-list">  <li v-for="item in datelist" v-text="item.value" :class="{premonth: item.previousmonth, nextmonth: item.nextmonth, selected: date === item.value && month === tmpmonth && item.currentmonth, invalid: validatedate(item)}" @click="selectdate(item)">  </li> </ul>
样式上就可以自己发挥了,怎么喜欢怎么写。需要注意的是循环日期可能会出现上个月或这个月的日期,我通过previuosmonth,currentmonth和nextmonth分别做了标记,对其他功能提供判断条件。
年份和月份的列表都是差不多的道理,年份列表的初始值我直接写在了data里,以当前年份为第一个,为了和月份保持一致,每次显示12个,都通过v-for渲染。
data () {  return {   yearlist: array.from({length: 12}, (value, index) => new date().getfullyear() + index)  } }
选择日期功能选择顺序是:年 -> 月 -> 日,所以我们可以通过一个状态变量来控制panel中显示的内容,绑定适合的函数切换显示状态。
<p>  <p class="type-year" v-show="paneltype === 'year'">   <ul class="year-list">    <li v-for="item in yearlist" v-text="item" :class="{selected: item === tmpyear, invalid: validateyear(item)}" @click="selectyear(item)" >    </li>   </ul>  </p>  <p class="type-month" v-show="paneltype === 'month'">   <ul class="month-list">    <li v-for="item in monthlist" v-text="item | month language" :class="{selected: $index === tmpmonth && year === tmpyear, invalid: validatemonth($index)}" @click="selectmonth($index)" >    </li>   </ul>  </p>  <p class="type-date" v-show="paneltype === 'date'">   <ul class="date-list">    <li v-for="item in datelist" v-text="item.value" track-by="$index" :class="{premonth: item.previousmonth, nextmonth: item.nextmonth, selected: date === item.value && month === tmpmonth && item.currentmonth, invalid: validatedate(item)}" @click="selectdate(item)">    </li>   </ul>  </p> </p>
选择日期的方法就不细说了,在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的方式传值。
<datepicker :value.sync="start"></datepicker> <!-- 现在min的值会随着start的变化而变化 --> <datepicker :value.sync="end" :min="start" ></datepicker>
增加了限制条件,对于不合法的日期,其按钮应该变为置灰状态,我用了比较时间戳的方式来判断日期是否合法,因为就算当前panel中的日期是跨年或是跨月的,通过日期构造函数创建时都会帮你转换成对应的合法值,省去很多判断的麻烦:
new date(2015, 0, 0).gettime() === new date(2014, 11, 31).gettime() //true new 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() <= new date(this.maxyear, this.maxmonth - 1, this.maxdate).gettime()){ return false } return true }
动态计算位置当页面右侧有足够的空间显示时,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 <= 300){ this.coordinates = {right: '0', top: `${window.getcomputedstyle(this.$el.children[0]).offsetheight + 4}px`} }else{ this.coordinates = {left: '0', top: `${window.getcomputedstyle(this.$el.children[0]).offsetheight + 4}px`} } } <!-- template中对应的动态style --> <p :style="coordinates"></p>
为了panel的显隐可以平滑过渡,可以使用transition做过渡动画,这里我简单地通过一个0.2秒的透明度过渡让显隐更平滑。
<p :style="this.coordinates" v-show="panelstate" transition="toggle"></p> //less syntax .toggle{  &-transition{   transition: all ease .2s;  }  &-enter, &-leave{   opacity: 0;  } }
中英文切换这里其实也很简单,这种多语言切换实质就是一个key根据不同的type而输出不同的value,所以使用filter可以很容易的实现它!比如渲染星期的列表:
<ul class="weeks">   <li v-for="item in weeklist" v-text="item | week language"></li>  </ul>   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 <script>  import datepicker from 'path/to/datepicker.vue'  export default {   components: { datepicker}  } </script>
如果是直接在浏览器中使用,那么我希望datepicker这个组件是暴露在全局下的,可以这么使用:
//index.html <html>  <script src="path/to/vue.js"></script>  <script src="path/to/datepicker.js"></script>  <body>   <p id="app"></p>   <script>    new vue({     el: '#app',     components: { datepicker }    })   </script>  </body> </html>
这里我选择了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.xvue 2.0已经发布有段时间了,现在把之前的组件适配到vue 2.0。迁移过程还是很顺利的,核心api改动不大,可以借助vue-migration-helper来找出废弃的api再逐步修改。这里只列举一些我需要修改的api。
filter2.0中的filter只能在mustache绑定中使用,如果想在指令式绑定中绑定过滤后的值,可以选择计算属性。我在月份和星期的显示中使用到了过滤器来过滤语言类型,但我之前是在指令式绑定中使用的filter,所以需要如下修改,:
//修改前 <p class="month-box" @click="chtype('month')" v-text="tmpmonth + 1 | month language"></p> //修改后,filter传参的方式也变了,变成了函数调用的风格 <p class="month-box" @click="chtype('month')">{{tmpmonth + 1 | month(language)}}</p>
移除$index和$key这两个属性不会在v-for中被自动创建了,如需使用,要在v-for中自行声明:
<li v-for="item in monthlist" @click="selectmonth($index)"></li> // <li v-for="(item, index) in monthlist" @click="selectmonth(index)"></li>
ready 生命周期移除ready从生命周期钩子中移除了,迁移方法很简单,使用mounted和this.$nexttick来替换。
prop.sync弃用prop的sync弃用了,迁移方案是使用自定义事件,而且datepicker这种input类型组件,可以使用表单输入组件的自定义事件作为替换方案。自定义组件也可以使用v-model指令了,但是必须满足两个条件:
接收一个value的prop
值发生变化时,触发一个input事件,传入新值。
所以datepicker的使用方式也不是<datepicker value.sync="now"></datepicker>了,而是<datepicker v-model="now"></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)
相信看了本文案例你已经掌握了方法,更多精彩请关注其它相关文章!
推荐阅读:
datepicker插件监听输入框
navigatorios组件的使用详解
ejsexcel模板在vue.js中的使用
以上就是datepicker怎么使用的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product