關於滑動翻頁,有很多優秀的插件可以使用,但是多多少少都有點大,所以自己試着完成一個組件來實現。(以左右滑動翻頁爲例)
1、主要思路
最主要的就是對三個觸摸事件的處理:touchstart、touchmove、touchend
在touchstart事件處理程序中記錄一些初始值,比如原始座標;在touchmove事件處理程序中計算實時滑動的距離,讓元素隨之一起偏移;在touchend事件處理程序中計算最終的滑動距離,大於闕值則滑動一整頁,小於則回到起始位置。
2、代碼實現
頁面結構:具體的組件結構和數據傳遞就不展示了,只列出編譯後的HTML結構如下:
基本樣式:inline-block用font-size: 0來隱藏間距
<style lang='scss'>
.ths_swiper-wrap {
white-space: nowrap;
display: inline-block;
font-size: 0;
.swiper{
position: relative;
display: inline-block;
width: 100vw;
text-align: center;
font-size: 14px;
}
}
</style>
初始設置:記錄頁面寬度、.ths_swiper-wrap元素的寬度、滾動的元素.swiper
mounted () {
this.pageWidth = document.documentElement.clientWidth
this.elementWidth = this.$refs.swiper.offsetWidth
this.swiperEles = this.$refs.swiper.querySelectorAll('.swiper')
},
滾動元素:這裏需要專門記錄的是,在.ths_swiper-wrap元素上監聽滑動事件,.ths_swiper-wrap元素和.swiper元素滑動時都會觸發。所以我一開始是使用.self修飾符,只監聽.ths_swiper-wrap元素的滾動,移動的也是.ths_swiper-wrap元素。
<div class="ths_swiper-wrap"
ref="swiper"
@touchstart.self="touchstart"
@touchmove.self="touchmove"
@touchend.self="touchend">
<slot></slot>
</div>
但是這樣做會有個問題,手指點在.swiper元素上時無法滑動,只有點在.swiper外 && .ths_swiper-wrap內(.ths_swiper-wrap的padding,或.swiper的margin)時才能滑動。所以,最終我選擇不是滑動.ths_swiper-wrap元素,而是滑動全部.swiper元素。
<div class="ths_swiper-wrap"
ref="swiper"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend">
<slot></slot>
</div>
事件處理:
touchstart (e) {
this.originalPos = e.touches[0].pageX
this.originalLeft = Number(this.swiperEles[0].style.left.split('px')[0])
},
touchmove (e) {
this.doSlide((e.touches[0].pageX - this.originalPos) / 2) // 除以2來控制滑動速度
},
touchend (e) {
let moveDistance = e.changedTouches[0].pageX - this.originalPos // >0 右滑,<0 左滑
let currentLeft = Number(this.swiperEles[0].style.left.split('px')[0])
if ((Math.abs(moveDistance) > 100 && ((moveDistance > 0 && currentLeft < 0) || (moveDistance < 0 && Math.abs(currentLeft) < this.elementWidth - this.pageWidth)))) {
// 滑動距離大於闕值100,且內容在邊界內時,滑動一整頁
let distance = moveDistance > 0 ? this.pageWidth : -this.pageWidth
this.doSlide(distance)
} else {
// 滑動回原處
this.doSlide(0)
}
},
doSlide (distance) {
this.swiperEles.forEach((element, index) => {
element.style.left = this.originalLeft + distance + 'px'
})
}
3、後期優化
上面實現了最基礎的滑動翻頁組件,算是第一版,後期還有很多需要優化的地方,比如每個.swiper元素的高度如果不統一,父級高度應該自適應;滑動時爲了提升性能,不需要滑動所有.swiper元素,只需要滑動當前和即將要進入的兩個元素即可等等。