目錄
前言
功能&期望
目錄結構
從Datepicker.vue入手
渲染日期列表
選擇日期功能
最大/小時間限制
动态计算位置
中英文切换
多种使用方式
适配 Vue 2.x
filter
移除$index和$key
ready 生命周期移除
prop.sync弃用
首頁 web前端 js教程 在Vue中有關datepicker的範例程式碼

在Vue中有關datepicker的範例程式碼

Jun 09, 2018 am 11:10 AM
vue

這篇文章主要介紹了使用Vue寫一個datepicker的範例,現在分享給大家,也給大家做個參考。

前言

寫入外掛是很有意思,也很鍛鍊人,因為這個過程中能發現許多的細節問題。在前端發展的過程中,jQuery無疑是一個重要的里程碑,圍繞著這個優秀專案也出現了很多優秀的插件可以直接使用,大大節省了開發者們的時間。 jQuery最重要的作用是跨瀏覽器,而現在瀏覽器市場雖不完美,但已遠沒有從前那麼慘,數據驅動視圖的思想倍受歡迎,大家開始使用前端框架取代jQuery,我個人比較喜歡Vue. js,所以想試著用Vue.js寫一個元件出來。

為了發佈到npm上,所以給專案位址改名字了,但內部程式碼沒有改,使用方法比之前方便。

GitHub位址: Here

功能&期望

這個datepicker目前只實作了一些常用的功能:

  1. 選擇時間(這話說得有點多餘)

  2. 最大/最小時間限制

  3. #中/英文切換(其實也就星期和月份需要切換)

  4. 可以.vue形式使用,也可在瀏覽器環境中直接使用

  5. 沒了。 。 。

目錄結構

萬事的第一步仍然是創建項目,只是單一組件,結構並不復雜,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 === &#39;year&#39;">
  <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 === &#39;month&#39;">
  <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 === &#39;date&#39;">
  <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 = &#39;date&#39;
 }
},
selectDate (date) {
 //validate logic above...
 //一次性全部赋值
 this.year = tmpYear
 this.month = tmpMonth
 this.date = date.value
 this.value = `${this.tmpYear}-${(&#39;0&#39; + (this.month + 1)).slice(-2)}-${(&#39;0&#39; + 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: &#39;0&#39;, top: `${window.getComputedStyle(this.$el.children[0]).offsetHeight + 4}px`}
 }else{
  this.coordinates = {left: &#39;0&#39;, 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 &#39;en&#39;:
    return {0: &#39;Su&#39;, 1: &#39;Mo&#39;, 2: &#39;Tu&#39;, 3: &#39;We&#39;, 4: &#39;Th&#39;, 5: &#39;Fr&#39;, 6: &#39;Sa&#39;}[item]
   case &#39;ch&#39;:
    return {0: &#39;日&#39;, 1: &#39;一&#39;, 2: &#39;二&#39;, 3: &#39;三&#39;, 4: &#39;四&#39;, 5: &#39;五&#39;, 6: &#39;六&#39;}[item]
   default:
    return item
  }
 }
}
登入後複製

多种使用方式

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

//App.vue
<script>
 import datepicker from &#39;path/to/datepicker.vue&#39;
 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: &#39;#app&#39;,
    components: { datepicker }
   })
  </script>
 </body>
</html>
登入後複製

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

module.exports = {
 entry: &#39;./index.js&#39;,
 output: {
  path: &#39;./dist&#39;,
  library: &#39;datepicker&#39;,
  filename: &#39;vue-datepicker.js&#39;,
  libraryTarget: &#39;umd&#39;
 },
 module: {
  loaders: [
   {test: /\.vue$/, loaders: [&#39;vue&#39;]},
   {test: /\.js$/, exclude: /node_modules/, loaders: [&#39;babel&#39;]}
  ]
 }
}
登入後複製

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

适配 Vue 2.x

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

filter

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

//修改前
<p class="month-box" @click="chType(&#39;month&#39;)" v-text="tmpMonth + 1 | month language"></p>
//修改后,filter传参的方式也变了,变成了函数调用的风格
<p class="month-box" @click="chType(&#39;month&#39;)">{{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指令了,但是必须满足两个条件:

  1. 接收一个value的prop

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

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

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

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

详细解读Vue.js中的组件使用方法以及作用?

AngularJS1.x应用迁移至React(详细教程)

在vue 2.0中如何实现购物车小球抛物线

以上是在Vue中有關datepicker的範例程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1323
25
PHP教程
1272
29
C# 教程
1251
24
vue中怎麼用bootstrap vue中怎麼用bootstrap Apr 07, 2025 pm 11:33 PM

在 Vue.js 中使用 Bootstrap 分為五個步驟:安裝 Bootstrap。在 main.js 中導入 Bootstrap。直接在模板中使用 Bootstrap 組件。可選:自定義樣式。可選:使用插件。

vue怎麼給按鈕添加函數 vue怎麼給按鈕添加函數 Apr 08, 2025 am 08:51 AM

可以通過以下步驟為 Vue 按鈕添加函數:將 HTML 模板中的按鈕綁定到一個方法。在 Vue 實例中定義該方法並編寫函數邏輯。

vue中的watch怎麼用 vue中的watch怎麼用 Apr 07, 2025 pm 11:36 PM

Vue.js 中的 watch 選項允許開發者監聽特定數據的變化。當數據發生變化時,watch 會觸發一個回調函數,用於執行更新視圖或其他任務。其配置選項包括 immediate,用於指定是否立即執行回調,以及 deep,用於指定是否遞歸監聽對像或數組的更改。

vue返回上一頁的方法 vue返回上一頁的方法 Apr 07, 2025 pm 11:30 PM

Vue.js 返回上一頁有四種方法:$router.go(-1)$router.back()使用 &lt;router-link to=&quot;/&quot;&gt; 組件window.history.back(),方法選擇取決於場景。

vue多頁面開發是啥意思 vue多頁面開發是啥意思 Apr 07, 2025 pm 11:57 PM

Vue 多頁面開發是一種使用 Vue.js 框架構建應用程序的方法,其中應用程序被劃分為獨立的頁面:代碼維護性:將應用程序拆分為多個頁面可以使代碼更易於管理和維護。模塊化:每個頁面都可以作為獨立的模塊,便於重用和替換。路由簡單:頁面之間的導航可以通過簡單的路由配置來管理。 SEO 優化:每個頁面都有自己的 URL,這有助於搜索引擎優化。

React與Vue:Netflix使用哪個框架? React與Vue:Netflix使用哪個框架? Apr 14, 2025 am 12:19 AM

NetflixusesAcustomFrameworkcalled“ Gibbon” BuiltonReact,notReactorVuedIrectly.1)TeamSperience:selectBasedonFamiliarity.2)ProjectComplexity:vueforsimplerprojects:reactforforforproproject,reactforforforcompleplexones.3)cocatizationneedneeds:reactoffipicatizationneedneedneedneedneedneeds:reactoffersizationneedneedneedneedneeds:reactoffersizatization needefersmoreflexibleise.4)

vue.js怎麼引用js文件 vue.js怎麼引用js文件 Apr 07, 2025 pm 11:27 PM

在 Vue.js 中引用 JS 文件的方法有三種:直接使用 &lt;script&gt; 標籤指定路徑;利用 mounted() 生命週期鉤子動態導入;通過 Vuex 狀態管理庫進行導入。

vue遍歷怎麼用 vue遍歷怎麼用 Apr 07, 2025 pm 11:48 PM

Vue.js 遍歷數組和對像有三種常見方法:v-for 指令用於遍歷每個元素並渲染模板;v-bind 指令可與 v-for 一起使用,為每個元素動態設置屬性值;.map 方法可將數組元素轉換為新數組。

See all articles