前言
better-scroll是一個非常非常強大的第三方庫 在移動端利用這個庫 不僅可以實現一個非常類似原生ScrollView的效果 也可以實現一個輪播圖的效果 這裡就先記錄一下自己實現這個效果的一些過程吧
思路
1.首先要確定自己的HTML結構 基本結構就是一個wrapper包含一個content
2.其次需要明白的一個頁面可以滾動的原理在於 當內容的高度超出了容器的高度才可以實現滾動 如果沒有超出 那麼就沒有滾動的必要 因此第一點需要實現的就是 獲取到所有內容的高度 由於實現的是一個輪播圖 所以其實整個頁面應該想象成這樣
![滾動原理](https://i.iter01.com/images/0e03dbe972478f10b2aa0d2058a266baf26697385976a0e39f4d12a738a55101.png)
這裡可以很清楚的看到 當頁面的橫向寬度超出了視口的寬度 因此也就可以實現滾動 綜上所述 可以看出 實現橫向輪播最重要的一點在於寬度 因此 我們首先要獲得的就是整個輪播圖的寬度
3.既然是個輪播圖 那麼使用者同時也需要知道的就是 當前播放的是第幾張圖 也就是常見的"小白點" 小白點的個數用於告訴使用者總共有幾張圖 而當前播放第幾張圖則可以在小白點上加上一些特殊樣式的方法來告知使用者
4.輪播圖也需要一些常見的屬性 例如 頁面渲染以後自動播放以及播放間隔 還有一個就是 是否支援迴圈輪播
快樂coding
理清思路以後 就可以開始幹活了 1.完善HTML結構 其實程式碼非常簡單 也就是建立兩個div 並且新增ref引用可以方便的通過ref屬性獲取上下文
<div class="slider"
ref="slider">
<div class="slider-content"
ref="sliderContent">
<slot></slot>
</div>
</div>
複製程式碼
這裡用了vue中非常常見的slot插槽 為的是當我們在外部呼叫這個slider元件的時候 可以方便的在外部傳入一些子元件
2.上文已經提到了一些控制slider的屬性 所以需要在元件的props裡接受這些屬性 便於我們在外部方便的控制這些屬性
props: {
// 是否迴圈播放
loop: {
type: Boolean,
default: true
},
// 是否自動播放
autoPlay: {
type: Boolean,
default: true
},
// 播放間隔
interval: {
type: Number,
default: 3000
}
}
複製程式碼
3.一些初始步驟的完成的差不多了以後 我們需要藉助到vue的一個生命週期鉤子 mounted
也就是當頁面渲染完畢以後 去獲取輪播圖的寬度以及初始化輪播圖的一些設定
mounted: function () {
setTimeout(() => {
this.setSliderWidth()
this.initSlider()
}, 20)
複製程式碼
這裡有一個小小的tips 就是 通常情況下 瀏覽器渲染dom的時間為17ms 所以這裡使用了一個延遲函式 在20ms以後去呼叫這些方法 也就是確保瀏覽器的dom被正確渲染 防止出現一些問題
4.上面只是呼叫了這個方法 還沒有實現這些方法 首先在設定寬度的方法裡 我們需要通過$refs.sliderContent
拿到上下文 並且通過一個$refs.slider.clientWidth
方法拿到當前螢幕寬度
然後遍歷這個容器 取得容器裡的所有內容 同時把獲取的內容寬度設定為這個螢幕的寬度 最後將所有的內容的寬度相加 就可以得到整個slider的寬度 說了這麼多 感覺很繞口 所以還是看下程式碼吧
// 設定slider的寬度
setSliderWidth: function (isResize) {
// 獲取slider裡的所有的子元素
this.children = this.$refs.sliderContent.children
// console.log(this.children)
// 計算寬度 = 圖片個數+每張圖片的寬度
let width = 0
// 獲取手機螢幕的寬度
let sliderWidth = this.$refs.slider.clientWidth
for (let i = 0; i < this.children.length; i++) {
// 獲取children裡的每一項內容
let child = this.children[i]
child.style.width = sliderWidth + 'px'
width += sliderWidth
}
if (this.loop) {
width += 2 * sliderWidth
}
this.$refs.sliderContent.style.width = width + 'px'
}
複製程式碼
這樣我們就獲取了整個slider的寬度 還有一個細節在於 當如果是loop的時候 better-scroll會在頭尾克隆兩份 所以寬度會需要*2 接下去就是實現一些初始化better-scroll的一些配置了 具體的引數內容可以從better-scorll官網上查詢到 這裡就不多做贅述了
// 設定寬度以後初始化slider
initSlider: function () {
this.slider = new BScroll(this.$refs.slider, {
scrollX: true,
scrollY: false,
momentum: false,
snap: {
loop: this.loop,
threshold: 0.3,
speed: 400
},
click: true
})
}
複製程式碼
5.實現上述兩個方法以後 其實輪播圖基本已經可以在頁面上看到了 大概就是長成這樣 不過這樣寫完以後 會發現輪播圖是沒有辦法自動輪播的以及當前顯示的是幾張圖的樣式並沒有正確顯示 所以接下去就是實現這兩個方法
ps:這裡的圖片資料來源什麼 是請求了QQ音樂banner的介面檔案
![輪播圖的效果](https://i.iter01.com/images/d7a47b55908f72f9ae761d1200fb6420a059a9498951634d05ddf44d65078f8a.png)
6.實現dots樣式的正確載入 這裡用到了vue中樣式的繫結
<div class="dots">
<span class="dot"
v-for="(item, index) of dots"
:class="{active:currentPageIndex === index}"
:key="index">
</span>
</div>
複製程式碼
也就是說 我們通過下標來繫結樣式 同時監聽一個better-scroll的'scrollEnd'事件 當滾動結束的時候呼叫getCurrentPage()
這個方法 這個方法會有一個返回值pageX 也就是橫向滾動到第幾頁 把這個返回值賦值給currentPageIndex 從而達到正確顯示樣式的目的
this.slider.on('scrollEnd', () => {
let page = this.slider.getCurrentPage().pageX
this.currentPageIndex = page
// 當滾動結束以後 如果是自動播放的話 那麼首先要清除定時器(防止手動拖動輪播圖以後圖片無法正確顯示)然後再次執行方法 才能實現輪播
if (this.autoPlay) {
clearTimeout(this.timer)
this.play()
}
})
複製程式碼
7.實現自動播放功能
better-scroll也提供了一個介面goToPage(x, y, time, easing)
顧名思義也就是轉到對應頁面 其中幾個引數分別代表 x表示橫向頁面 y表示縱向頁面 time表示動畫執行時間 easing一般不建議修改 有了這個介面 其實就非常輕鬆了 我們只需要在methods裡再寫一個Play方法 具體的思路就是 通過currentPageIndex+=1得到下一張要播放的圖片的索引 同時當索引值達到圖片陣列的長度的時候將要索引重新賦值為0就好了 並在頁面渲染了以後呼叫就可以了
play: function () {
let playPage = this.currentPageIndex + 1
if (playPage === this.children.length - 2) {
playPage = 0
}
setTimeout(() => {
this.slider.goToPage(playPage, 0, 400)
}, this.interval)
}
複製程式碼
這裡也有個細節就是 當設定這個輪播圖為迴圈滾動的時候 better-scroll會自動在頭尾各克隆一份圖片 所以長度需要減去2 這樣就可以實現輪播圖的自動播放了
###總結 到這裡就成功通過better-scroll實現了一個輪播圖的實現 具體的過程其實不算多難 主要就是理清思路 就好啦!衝鴨!