Maison >interface Web >js tutoriel >Exemple de code pour le sélecteur de date dans Vue

Exemple de code pour le sélecteur de date dans Vue

亚连
亚连original
2018-06-09 11:10:331786parcourir

Cet article présente principalement un exemple d'utilisation de Vue pour écrire un sélecteur de date. Maintenant, je le partage avec vous et le donne comme référence.

Avant-propos

L'écriture de plug-ins est très intéressante et très stimulante, car de nombreux détails peuvent être découverts au cours du processus. Dans le processus de développement front-end, jQuery constitue sans aucun doute une étape importante. Autour de cet excellent projet, de nombreux excellents plug-ins ont vu le jour qui peuvent être utilisés directement, ce qui fait gagner beaucoup de temps aux développeurs. Le rôle le plus important de jQuery est multi-navigateur. Bien que le marché des navigateurs ne soit pas parfait aujourd'hui, il est loin d'être aussi misérable qu'avant. L'idée des vues basées sur les données est très populaire. frameworks front-end pour remplacer jQuery. Personnellement, je préfère Vue js, je veux donc essayer d'écrire un composant en utilisant Vue.js.

Afin de publier sur npm, j'ai changé le nom de l'adresse du projet, mais le code interne n'a pas été modifié et l'utilisation est plus pratique qu'avant.

Adresse GitHub : ici

Fonctions et attentes

Ce sélecteur de date n'implémente actuellement que certaines fonctions courantes :

  1. Sélectionner l'heure (ce est un peu redondant)

  2. Délai maximum/minimum

  3. Changement chinois/anglais (en fait, seuls la semaine et le mois doivent être commutés )

  4. peut être utilisé sous forme .vue ou directement dans l'environnement du navigateur

  5. Pas plus. . .

Structure du répertoire

La première étape consiste toujours à créer un projet. Il ne s'agit que d'un seul composant et la structure n'est pas compliquée. Datepicker.vue est la plus importante. fichier de composant, dist est le dossier de sortie de webpack, index.js est le fichier d'entrée pour l'empaquetage du webpack et enfin est le fichier de configuration du webpack, qui est utilisé pour empaqueter nos fichiers de bibliothèque. La structure du projet est donc la suivante :

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

Commencez avec Datepicker.vue

L'écriture de composants Vue en .vue est une manière particulière d'écrire. Chaque fichier Vue comprend un modèle, un script et un style. Dans les trois parties, il est préférable de ne pas utiliser le modèle comme instance de fragment, de sorte que la couche la plus externe soit d'abord recouverte d'une couche de p, qui est utilisée comme élément racine de l'ensemble du composant. Un sélecteur de date se compose généralement de deux parties, une zone de saisie utilisée pour afficher la date et un panneau utilisé pour sélectionner la date. Parce que j'ai trouvé que la saisie évoquerait automatiquement le clavier du terminal mobile, je n'ai pas utilisé de saisie et j'ai directement utilisé p. simulation, en cliquant sur L'événement détermine la visibilité du panneau. La valeur est le résultat final et doit communiquer avec le composant parent, donc la valeur est écrite comme prop et value.sync="xxx" est utilisée dans le composant parent. La valeur du sélecteur de date est liée de manière bidirectionnelle au xxx du. composant parent.

<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>

Liste des dates de rendu

Un mois comporte au moins 28 jours Si le dimanche est disposé au début, alors au moins 4 lignes sont nécessaires (la 1ère se trouve être le dimanche), mais chacun Le nombre de jours dans le mois est généralement de 30 ou 31, et le 1er n'est pas nécessairement un dimanche, donc je l'ai simplement conçu en fonction de la situation la plus courante, avec un total de 6 lignes Les places qui ne sont pas remplies dans le. les dates du mois en cours sont remplies avec les dates du mois précédent ou du mois suivant, ce qui facilite le calcul, et la hauteur du panneau ne changera pas lors du changement de mois. Le tableau de listes de dates doit être calculé dynamiquement. Vue fournit l'attribut calculé, donc la liste de dates dateList est directement écrite comme un attribut calculé. Ma méthode consiste à fixer la liste de dates dans un tableau d'une longueur de 42, puis à la remplir avec les dates de ce mois, du mois dernier et du mois suivant dans l'ordre.

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
}

Ici, nous utilisons Array.from pour initialiser un tableau, transmettre un Array Like, le convertir en tableau et utiliser arr[arr.length] et [{}].concat lors de l'épissage de chaînes . (arr) Cette méthode a de meilleures performances car j'ai appris de JsTips. Les liens connexes seront publiés à la fin de l'article.
De cette façon, la liste de dates est construite et est rendue à l'aide d'une boucle v-for dans le modèle

<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>

Vous pouvez utiliser le style pour écrire ce que vous voulez. Il convient de noter que la date du cycle peut apparaître le mois dernier ou ce mois-ci. Je l'ai marquée respectivement via previuosMonth, currentMonth et nextMonth pour fournir des conditions de jugement pour d'autres fonctions.
Les listes d'année et de mois sont similaires. J'ai écrit la valeur initiale de la liste d'année directement dans les données, avec l'année en cours comme première afin d'être cohérente avec le mois, 12 sont affichées à chaque fois via v. -pour le rendu.

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

Fonction de sélection de date

L'ordre de sélection est : année-> mois-> la liaison est appropriée. La fonction change l'état d'affichage.

<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>

Je n'entrerai pas dans les détails sur la méthode de sélection de la date. Attribuez des valeurs aux variables année et mois dans selectYear et selectMonth, puis poussez le panelType à l'étape suivante respectivement pour réaliser la fonction de sélection de date.

Cependant, vous ne souhaitez peut-être pas que la valeur réelle de l'année et du mois en cours change avant de sélectionner la date, donc dans ces méthodes, vous pouvez d'abord attribuer la valeur sélectionnée à une variable temporaire, puis attendre que seletDate Le sexe est tout attribué.

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
}

Durée maximale/minimale

La valeur maximale/minimale doit être transmise à partir du composant parent, des accessoires doivent donc être utilisés. De plus, cette valeur peut être une chaîne. , et cela devrait être OK est une variable (par exemple, s'il y a deux sélecteurs de date en même temps, la date du second ne peut pas être supérieure à la première), donc la valeur doit être transmise en utilisant la liaison dynamique.

<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的使用方式也不是f2711184ba1ee7ec6aa7b9dc5d2771bd736fc7563f791c0444464598257dec0b了,而是bad5218a9f314e0b4262fb54ca286ace736fc7563f791c0444464598257dec0b。组件自身向父级传值的方式也不一样了:

//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中如何实现购物车小球抛物线

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn