Maison > Article > interface Web > mise en œuvre de vue.js pour imiter l'expérience de développement de composants de sélection de temps iOS natifs
Préface
J'ai regardé VUE au cours des derniers mois, puis j'ai essayé d'implémenter certains composants en utilisant uniquement des js+vue . Composant de sélection de temps sur PC Il s'agit de la première implémentation de la sélection de temps sur PC Cela se fait également du côté mobile, je souhaite donc implémenter le
sélecteur de temps du côté mobile. Je l'ai implémenté sur mobile. L'idée et le processus du sélecteur de temps d'effet spécial à molette de défilement de fin. L'ensemble du composant est construit sur la base de vue-cli
Fonction1. Sélection de l'heure [
A.年月日选择
B.年月日小时分钟选择Sélection des heures et des minutes D. Sélection des minutes. ]
2. Effet de molette de défilement [
A.构成一个圆环首尾相连B. Ne constitue pas une connexion de bout en bout]
3. apparaît si l'heure sélectionnée dépasse la plage), minutes Réglage de l'intervalle
4.
Multi-langueRéglage5. Le réglage du format de l'heure répond aux règles de réglage de aaaa/MM/jj HH:mm<.>6. UE est proche de l'effet natif d'iOS
7. L'extension peut non seulement sélectionner l'heure, mais peut également transmettre des données de sélection de liaison personnalisées
Ici, nous parlons principalement de la mise en œuvre de la molette de défilement infinie
Préparation des données 1
Ici, utilisons
天une façon intelligente d'obtenir le nombre de jours dans un mois.
dayList () { /* get currentMonthLenght */ let currentMonthLength = new Date(this.tmpYear, this.tmpMonth + 1, 0).getDate(); /* get currentMonth day */ let daylist = Array.from({length: currentMonthLength}, (value, index) => { return index + 1 }); return daylist },
yearListdayList
monthList
hourListPour stocker les données de base, la préparation des données se termine ici.
minuteList
StatiqueRéalisation de l'effetIl existe de nombreuses façons de réaliser l'effet statique de la molette de défilement1 Effet visuel 3D [ajouter une ombre]
2. . Effet 3D réel[ CSS3D]
我把实现效果大致分为上面2种,具体的大家可以自己搜索相关资料,这里展开涉及太多就带过好了
Explication
Nous voyons d'abord l'effet de sélection iOS natif lorsque. saisie Il y a une différence entre la molette de défilement dans la plage de sélection et en dehors de la plage de sélection
Donc afin d'obtenir cette différence d'effet, j'ai choisi d'utiliser 2 structures dom pour implémentez-le, un dom implémente la molette de défilement et un dom implémente la molette de défilement. DOM réalise l'effet de sélection noire, de sorte qu'une fois lié, il y aura une différence similaire à l'effet d'origine
<.> Installer diverses options du DOM, ici seules celles du jour sont données,
picker-panel
Une boîte la plus à l'extérieur contenant les données du ciel,
box-day
réaliser les 2 lignes sélectionnées,
check-line
Les données de l'effet noir les plus à l'extérieur,
day-list
Partie de la molette de défilement grise
day-wheel
<p class="picker-panel"> <!--other box--> <p class="box-day"> <p class="check-line"></p> <p class="day-checked"> <p class="day-list"> <p class="list-p" v-for="day in renderListDay"> {{day.value}} </p> </p> </p> <p class="day-wheel"> <p class="wheel-p" v-for="day in renderListDay" transform: rotate3d(1, 0, 0, 80deg) translate3d(0px, 0px, 2.5rem);> {{day.value}} </p> </p> </p> <!--other box--> </p>
.day-wheel{ position: absolute; overflow: visible; height: px2rem(68px); font-size: px2rem(36px); top:px2rem(180px); left: 0; right: 0; color:$unchecked-date; -webkit-transform-style: preserve-3d; transform-style: preserve-3d; .wheel-p{ height: px2rem(68px); line-height: px2rem(68px); position: absolute; top:0; width: 100%; text-align: center; -webkit-backface-visibility: hidden; backface-visibility: hidden; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } }
transform-style: preserve-3d;
La partie derrière le volant est automatiquement masquée
-webkit-backface-visibility: hidden;
Utilisé pour positionner la roue
postition:absolute;
L'angle de rotation de chaque donnée Et le côté de la molette de défilement
transform: rotate3d(1, 0, 0, 80deg) translate3d(0px, 0px, 2.5rem);Le rayon du cercle
L'angle et le principe de construction de chaque rotation de données
Comme indiqué ci-dessus
est l'effet de notre vue stéréo avec molette de défilement, r est le 2,5rem dans notre css traduit 3d(0px,0px,2.5rem), S'il n'y a pas ce CSS, toutes les données seront rassemblées au centre du cercle
L'image ci-dessus n'est pas une rotation (le rouge représente l'effet de données que nous voyons)
L'image ci-dessus est tournée (le rouge et l'orange représentent l'effet de données que nous voyons)
Arc bleu L'angle représenté est le même (cela implique la connaissance des angles), et c'est aussi le angle de rotation visuel, qui est le 80 degrés dans le CSS rotate3d. Ce que je fais est espacé de 20 degrés, de sorte qu'en fait nous faisons uniquement pivoter l'axe des x et tournons d'ailleurs l'angle central du cercle s'étend sur tout l'anneau. Un cercle complet peut contenir des données 360/20, et nous pouvons voir les données frontales à l'œil nu, donc après un certain angle, elles ne devraient pas nous être visibles, et -webkit-backface-visibility: Hidden cette phrase signifie Cela ; travaillé.
L'effet est similaire à l'image ci-dessous
这里我们发现轮子装不完所有数据,而且我们要实现数据循环
Il y a donc une deuxième préparation des données
Préparation des données 2
Ici, nous utilisons également notre dayList comme données initiales [1, 2, 3, 4,..., 30, 31] Ici, nous prenons 19 données à chaque fois comme données de rendu, et nous avons besoin de renderListDay le rendu initial est [ 23,24,25,26,27,28,29,30,31,1,2,3,4,5,6,7,8,9,10]Parce que c'est juste de prendre le chiffre du milieu C'est le premier (uniquement lors de l'initialisation)
La méthode de récupération des données est inférieure à 0, en arrière et supérieure à 0, et la récupération en avant,
renderListDay(){ let list = []; for (let k = this.spin.day.head; k <= this.spin.day.last; k++) { let obj = { value: this.getData(k, 'day'), index: k, }; list.push(obj) } return list },est supérieure à la longueur des données d'origine. Utilisez le calcul en % pour obtenir l'indice correspondant à la plage normale, donc le spin ci-dessus est notre fourchette pour récupérer les données (initialement de -9 à 9)
L'angle de rotation de chaque donnée (Le demi-cercle supérieur est positif, le demi-cercle inférieur est négatif)
getData(idx, type){ //... else if (type == 'day') { return this.dayList[idx % this.dayList.length >= 0 ? idx % this.dayList.length : idx % this.dayList.length + this.dayList.length]; } //... },
<p class="wheel-p" v-for="day in renderListDay" v-bind:data-index="day.index" v-bind:style="{transform: 'rotate3d(1, 0, 0, '+ (-day.index)*20%360+'deg) translate3d(0px, 0px, 2.5rem)'}">{{day.value}}{{day.value}}</p>
接着需要旋转到我们需要的角度,跟我们的初始化时间对上,this.orDay-this.DayList[0] 是获取偏移量来矫正角度
this.$el.getElementsByClassName('day-wheel')[0].style.transform = 'rotate3d(1, 0, 0, ' + (this.orDay - this.dayList[0]) * 20 + 'deg)';
增加touch事件
剩下的事就很好处理了,给对应的dom绑定事件根据touchmove的距离来转换成旋转的角度 和check-list的位移这里translateY是用来记录实际移动的距离的,最后输出需要算入偏移量
<p class="box-day" v-on:touchstart="myTouch($event,'day')" v-on:touchmove="myMove($event,'day')" v-on:touchend="myEnd($event,'day')"> <p class="check-line"></p> <p class="day-checked"> <p class="day-list" data-translateY="0" style="transform: translateY(0rem)"> <p class="list-p" v-for="day in renderListDay" v-bind:data-index="day.index"> {{day.value}} </p> </p> </p> <p class="day-wheel" style=" transform: rotate3d(1, 0, 0,0deg)"> <p class="wheel-p" v-for="day in renderListDay" v-bind:data-index="day.index" v-bind:style="{transform: 'rotate3d(1, 0, 0, '+ (-day.index)*20%360+'deg) translate3d(0px, 0px, 2.5rem)'}"> {{day.value}} </p> </p> </p>
惯性滚动
这个实现我是用了一个 cubic-bezier(0.19, 1, 0.22, 1)
判断手势是不是flicker 如果是flicker通过一个瞬时速度来算出位移,和时间,然后一次性设置,然后用transition做惯性滚动,
普通拖动 设置1秒
这个实际效果还是有点不好,以后来改进。
其他功能的实现
这里不做详细说明了
总结
自适应方面用了手淘的解决方案
这次实现这个组件最困难的就是实现无限滚动,和无限滚动的渲染数据的构造,接着就是惯性滚动的实现。
已知问题
1.惯性滚动不完美
2.无限滚动实现了。非无限滚动没实现,就是渲染数据就是[1,2,3,4,5,6,7,8,9,10]
3.现在选择必须 年月日 或者年月日小时分钟 不能单独选小时或者分钟
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!