Before the earliest implementation of a similar time-selection plug-in, but the scope of application is too narrow, simply to publish this implementation recently, rewrite a high-reuse Vue component.
Support Android 4.0 or above, Safari 7 or above
Effect Preview
GitHub
Wheel Part main DOM structure
<Template><Divclass="Pd-select-item" ><Divclass="Pd-select-line" ></Div><Ulclass= "pd-select-list" > <li class= "Pd-select-list-item" >1</li> </ul> <ul class= "Pd-select-wheel" > <li class=" Pd-select-wheel-item ">1</li> </ul> </div> </TEMPLATE>
Props
props: { data: { type: Array, true }, type: { type: String, default: ‘cycle‘ }, value: {} }
Set the CSS style to center vertically
.pd-select-line, .pd-select-list, .pd-select-wheel { position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%);}.pd-select-list { overflow: hidden;}
Wheel 3d style settings
/* 滚轮盒子 */.pd-select-wheel { transform-style: preserve-3d; height: 30px;}/* 滚轮单项 */.pd-select-wheel-item { white-space: nowrap; text-overflow: ellipsis; backface-visibility: hidden; position: absolute; top: 0px; width: 100%; overflow: hidden;}
Main Note 2 Properties transform-style: preserve-3d; backface-visibility: hidden;
The first one is the 3d layout, the interface 3D, the second is to let the wheel behind the auto-hide (red part, the back of the DOM node will be automatically hidden)
How to implement a 3D roller
Box main this CSStransform: rotate3d(1, 0, 0, x deg);
Item mainly uses this CSStransform: rotate3d(1, 0, 0, xdeg) translate3d(0px, 0px, [x]px);
The above 2 pictures show the translate3d(0px, 0px, [x]px); effect of this sentence [x] is the radius of the circle
As you can see from the above figure, we just need to rotate each DOM itself, and then translate3d(0px, 0px, [x]px); expand each DOM by expanding
The ring is formed. α is the angle at which each DOM rotates itself, because it only uses 0 to 180 °, so a box is used to mount the DOM.
Row heights and angular calculations
Known both sides and angle calculate the third side length ~=34px
Http://tool.520101.com/calcul ...
Infinite Wheel implementation
/* 滚轮展示大小限定 */spin: {start: 0, end: 9, branch: 9}/* 获取spin 数据 */ getSpinData (index) { index = index % this.listData.length return this.listData[index >= 0 ? index : index + this.listData.length] } /* 模运算 获取数组有的索引 这样就构成 圆环了 */
Touchend Do special treatment
Set the SETCSS type in the touchend to take the scrolling data, so that when the stop is a lattice of accurate rotation in place
// other code .... /* 计算touchEnd移动的整数距离 */ let endMove = margin let endDeg = Math.round(updateDeg / deg) * deg if (type === ‘end‘) { this.setListTransform(endMove, margin) this.setWheelDeg(endDeg) } else { this.setListTransform(updateMove, margin) this.setWheelDeg(updateDeg) } // other code ....
Inertia Slow motion
Other code ..... setwheeldeg (updatedeg, type, time =1000) {if (type = = =' End ') {this. $refs. wheel.style.webkitTransition =' Transform${time}ms Cubic-bezier (0.19, 1, 0.22, 1) 'this. $refs. Wheel.style.webkitTransform =' Rotate3d (1, 0, 0,${updatedeg}deg) '}else {this. $refs. wheel.style.webkitTransition =‘‘this. $refs. Wheel.style.webkitTransform =' Rotate3d (1, 0, 0,${updatedeg}deg) '}}setlisttransform (Translatey =0, margintop =0, type, time =1000) {if (type = = =' End ') {this. $refs. list.style.webkitTransition =' Transform${time}ms Cubic-bezier (0.19, 1, 0.22, 1) 'this. $refs. List.style.webkitTransform =' Translatey (${translatey-This.spin.branch *34}PX) 'this. $refs. List.style.marginTop =`${-margintop}px ' this. $refs. List.setattribute ( ' scroll ', translatey) console.log ( ' End ')} Span class= "Hljs-keyword" >else {this. $refs. list.style.webkitTransition = " this. $refs. list.style.webkitTransform = Translatey (${translatey-this.spin.branch * 34}px" this. $refs. List.style.marginTop = Span class= "Hljs-subst" >${-margintop}px ' this. $refs. List.setattribute ( scroll ', Translatey)}}//other code ...
Gets the currently selected value
/* 在设置完css后获取值 */ setStyle (move, type, time) { // ...other code /* 设置$emit 延迟 */ setTimeout(() => this.getPickValue(endMove), 1000) // ...other code}/* 获取选中值 */ getPickValue (move) { let index = Math.abs(move / 34) let pickValue = this.getSpinData(index) this.$emit(‘input‘, pickValue) }
Initialize settings
Mounted () {/* Event Binding */this. $el. AddEventListener (' Touchstart ',This.itemtouchstart)this. $el. AddEventListener (' Touchmove ',This.itemtouchmove)this. $el. AddEventListener (' Touchend ', this.itemtouchend)/ * Initialization status * /Let index = this.listData.indexOf (this.value) if (Index = = -1) { Console.warn (' current initial value does not exist, please check the rear listdata range!! ') this.setlisttransform () This.getpickvalue (0)} else {let move = index * +/* due to top slip * * This.setstyle (-move) this.setlisttransform (-move,-move)}
When displayed as a non-infinite wheel
Here we have a good judgment, that is, the distance of the scroll must not exceed the original number of the array length *34, and cannot be less than 0 (the actual code involved in the direction)
/* Determine updatemove maximum distance according to the roller type line or cycle */if (This.type = = =' line ') {if (Updatemove > 0) {Updatemove = 0} if (Updatemove <-(this.listData.length- 1) * Single Height) {updatemove =-(this.listData.length- 1) * Singleheight}} /* control wheel display effect by type */Sethidden (index) { if (this.type = = = ' line ') { return index < 0 | | index > this.listData.length- 1 } else { return false}},
The DOM structure also adds a corresponding response
<Divclass="Pd-select-item" ><Divclass="Pd-select-line" ></Div><Divclass="Pd-select-list" ><Ulclass="Pd-select-ul"Te ="List" ><Liclass="Pd-select-list-item"V-for="El,index in RenderData": class="{' Hidden ': Sethidden (El.index)}": key="Index" >{{el.value}}</Li></Ul></Div><Ulclass= "Pd-select-wheel" ref= "wheel" > Span class= "Hljs-tag" ><li class= " Pd-select-wheel-item ":class=" {' Hidden ': Sethidden (El.index)} " :style= "setwheelitemdeg (el.index)" : Index= "El.index" v-for= "El,index in RenderData ":key=" index ">{{el.value}} </li> </ ul> </DIV>
Vue implements iOS native picker effect (Implementation thinking analysis)