這里再安利一下better-scroll這個(gè)組件庫,該庫的源代碼結(jié)構(gòu)清晰,借鑒了vue源碼的組織形式。better-scroll提供的各功能模塊相互獨(dú)立,易于閱讀,對(duì)初學(xué)者非常友好,建議學(xué)習(xí)一下。
另外,我們可以借助better-scroll提供的功能封裝出更為復(fù)雜的組件。這里要說的picker選擇器組件就是基于better-scroll提供的特性實(shí)現(xiàn)的。

實(shí)現(xiàn)原理
這里主要借助better-scroll提供的wheel屬性,利用該屬性并配合相應(yīng)的html結(jié)構(gòu)以及css樣式可以很簡單的實(shí)現(xiàn)選擇器組件。
<template>
<div class="wheel-wrapper" ref="wrapper">
<ul class="wheel-scroller">
<li class="wheel-item" v-for="index in data">{{index}}</li>
</ul>
</div>
</template>
<script>
const EVENT_CHANGE = 'change'
import BScroll from 'better-scroll'
export default {
props: {
data: {
type:Array,
default:function(){
return []
}
},
selectedIndex: {
type:Number,
default:0
}
},
data() {
return {
}
},
mounted() {
this.$nextTick(() => {
this._createWheel().enable()
})
},
methods: {
_createWheel() {
if (!this.wheels) {
const wheel = this.wheels = new BScroll(this.$refs.wrapper, {
wheel: {
selectedIndex: this.selectedIndex,
wheelWrapperClass: 'wheel-scroller',
wheelItemClass: 'wheel-item',
rotate: 0
},
observeDOM: false
})
wheel.on('scrollEnd', () => {
//滾動(dòng)完成之后獲取當(dāng)前選取的索引值
this.$emit(EVENT_CHANGE,wheel.getSelectedIndex())
})
} else {
this.wheels.refresh()
}
return this.wheels
},
}
}
</script>
<style lang="scss" scoped>
.wheel-wrapper{
height: 100px;
overflow: hidden;
.wheel-scroller{
.wheel-item{
line-height:24px;
}
}
}
</style>
以上代碼實(shí)現(xiàn)的效果圖如下所示,第一行即為當(dāng)前選中的選項(xiàng),我們接下來要做的事情就是給選中的選項(xiàng)設(shè)計(jì)樣式。

樣式設(shè)計(jì)
<template>
<div class="relative">
<div class="mask-top absolute"></div>
<div class="mask-bottom absolute"></div>
<div class="wheel-wrapper" ref="wrapper">
<ul class="wheel-scroller">
<li class="wheel-item" v-for="index in data">{{index}}</li>
</ul>
</div>
</div>
</template>
<script>
const EVENT_CHANGE = 'change'
import BScroll from 'better-scroll'
export default {
props: {
data: {
type:Array,
default:function(){
return []
}
},
selectedIndex: {
type:Number,
default:0
}
},
data() {
return {
}
},
mounted() {
this.$nextTick(() => {
this._createWheel().enable()
})
},
methods: {
_createWheel() {
if (!this.wheels) {
const wheel = this.wheels = new BScroll(this.$refs.wrapper, {
wheel: {
selectedIndex: this.selectedIndex,
wheelWrapperClass: 'wheel-scroller',
wheelItemClass: 'wheel-item',
rotate: 0
},
observeDOM: false
})
wheel.on('scrollEnd', () => {
//滾動(dòng)完成之后獲取當(dāng)前選取的索引值
this.$emit(EVENT_CHANGE,wheel.getSelectedIndex())
})
} else {
this.wheels.refresh()
}
return this.wheels
},
}
}
</script>
<style lang="scss" scoped>
.relative{
position: relative;
}
.absolute{
position: absolute;
}
.mask-top{
height:24px;
width:100%;
top:0;
border-bottom:1px solid red;
}
.mask-bottom{
height:24px;
width:100%;
top:24px;
border-bottom:1px solid red;
background:red;
z-index:-1;
}
.wheel-wrapper{
height: 100px;
overflow: hidden;
.wheel-scroller{
margin-top:24px;
.wheel-item{
line-height:24px;
}
}
}
</style>
以上代碼實(shí)現(xiàn)的效果如下圖所示,這里只給出了簡單的原理以及演示,具體實(shí)現(xiàn)可根據(jù)自己的實(shí)際情況設(shè)計(jì)。

擴(kuò)展
這里只演示了單列選擇器組件,相對(duì)來說簡單,我們?cè)陂_發(fā)時(shí)常遇到的情形是多列的情況,再復(fù)雜就是各列存在聯(lián)動(dòng)關(guān)系。至于多列的設(shè)計(jì),這里只需要?jiǎng)?chuàng)建多個(gè)better-scroll的實(shí)例即可。若存在多列聯(lián)動(dòng)的情形,需要根據(jù)滾動(dòng)情況動(dòng)態(tài)的輸入相應(yīng)了list,這里不再對(duì)詳細(xì)設(shè)計(jì)做贅述。
總結(jié)
基于better-scroll還可以設(shè)計(jì)出很多復(fù)雜實(shí)用的組件,在后續(xù)會(huì)不斷總結(jié)。。。。。