效果圖:
配置環(huán)境
因為用到的是 vue-cli 和 better-scroll,所以首先要安裝 vue-cli,然后再 npm 安裝 better-scroll。
簡單介紹一下 better-scroll:
better-scroll 是一款重點解決移動端(已支持 PC)各種滾動場景需求的插件。它的核心是借鑒的 iscroll 的實現(xiàn),它的 API 設(shè)計基本兼容 iscroll,在 iscroll 的基礎(chǔ)上又?jǐn)U展了一些 feature 以及做了一些性能優(yōu)化。
better-scroll 是基于原生 JS 實現(xiàn)的,不依賴任何框架。它編譯后的代碼大小是 63kb,壓縮后是 35kb,gzip 后僅有 9kb,是一款非常輕量的 JS lib。
除了這兩,還使用 scss、vue-lazyload。scss 預(yù)處理器,大家都懂,用別的也一樣。lazyload 實現(xiàn)懶加載,不用也可以,主要是優(yōu)化一下體驗。
數(shù)據(jù)直接使用了網(wǎng)易云的歌手榜單, 偷懶就直接放在 data 里面了。
CSS 樣式我就不貼了,直接看源碼就可以了。
實現(xiàn)基本樣式
直接使用 v-for 和 雙側(cè)嵌套實現(xiàn)歌手列表、以及右側(cè)索引欄。
HTML 結(jié)構(gòu):
class="list-group"
:key="group.id"
ref="listGroup">
class="list-group-item":key="item.id">
class="item"
:data-index="index"
:key="item.id"
>
shortcutList 是通過計算屬性得到的,取 title 的第一個字符即可。
shortcutList() {
return this.singers.map((group) => {
return group.title.substr(0, 1)
})
}
使用 better-scroll
使用 better-scroll 實現(xiàn)滾動。對了,使用的時候別忘了用 import 引入。
created() {
// 初始化 better-scroll 必須要等 dom 加載完畢
setTimeout(() => {
this._initSrcoll()
}, 20)
},
methods: {
_initSrcoll () {
console.log('didi')
this.scroll = new BScroll(this.$refs.listView, {
// 獲取 scroll 事件,用來監(jiān)聽。
probeType:3
})
}
}
使用 created 方法進行 better-scroll 初始化,使用 setTimeout 是因為需要等到 DOM 加載完畢。不然 better-scroll 獲取不到 dom 就會初始化失敗。
這里把方法寫在兩 methods 里面,這樣就不會看起來很亂,直接調(diào)用就可以了。
初始化的時候傳入兩 probeType: 3,解釋一下:當(dāng) probeType 為 3 的時候,不僅在屏幕滑動的過程中,而且在 momentum 滾動動畫運行過程中實時派發(fā) scroll 事件。如果沒有設(shè)置該值,其默認(rèn)值為 0,即不派發(fā) scroll 事件。
順便給大家推薦一個裙,它的前面是 537,中間是631,最后就是 707。想要學(xué)習(xí)前端的小伙伴可以加入我們一起學(xué)習(xí),互相幫助。群里每天晚上都有大神免費直播上課,如果不是想學(xué)習(xí)的小伙伴就不要加啦。
(537-631-707)
給索引添加點擊事件和移動事件實現(xiàn)跳轉(zhuǎn)
首先需要給索引綁定一個 touchstart 事件(當(dāng)在屏幕上按下手指時觸發(fā)),直接使用 v-on 就可以了。然后還需要給索引添加一個 data-index 這樣就可以獲取到索引的值,使用 :data-index="index"。
class="item"
:data-index="index"
:key="item.id"
@touchstart="onShortcutStart"
@touchmove.stop.prevent="onShortcutMove"
>
綁定一個 onShortcutStart 方法。實現(xiàn)點擊索引跳轉(zhuǎn)的功能。再綁定一個 onShortcutMove 方法,實現(xiàn)滑動跳轉(zhuǎn)。
created() {
?// 添加一個 touch 用于記錄移動的屬性
this.touch = {}
// 初始化better-scroll必須要等dom加載完畢
setTimeout(() => {
this._initSrcoll()
}, 20)
},
methods: {
_initSrcoll () {
this.scroll = new BScroll(this.$refs.listView, {
probeType:3,
click: true
})
},
onShortcutStart(e) {
?// 獲取到綁定的 index
let index = e.target.getAttribute('data-index')
?// 使用 better-scroll 的 scrollToElement 方法實現(xiàn)跳轉(zhuǎn)
this.scroll.scrollToElement(this.$refs.listGroup[index])
?// 記錄一下點擊時候的 Y坐標(biāo) 和 index
let firstTouch = e.touches[0].pageY
this.touch.y1 = firstTouch
this.touch.anchorIndex = index
},
onShortcutMove(e) {
?// 再記錄一下移動時候的 Y坐標(biāo),然后計算出移動了幾個索引
let touchMove = e.touches[0].pageY
this.touch.y2 = touchMove
// 這里的 16.7 是索引元素的高度
let delta = Math.floor((this.touch.y2 -this.touch.y1) / 18)
// 計算最后的位置
// * 1 是因為 this.touch.anchorIndex 是字符串,用 * 1 偷懶的轉(zhuǎn)化一下
let index =this.touch.anchorIndex * 1 + delta
this.scroll.scrollToElement(this.$refs.listGroup[index])
}
}
這樣就可以實現(xiàn)索引的功能了。
當(dāng)然這樣是不會滿足我們的對不對,我們要加入炫酷的特效呀。比如索引高亮什么的~~
移動內(nèi)容索引高亮
emmm,這個時候就有點復(fù)雜啦。但是有耐心就可以看懂滴。
我們需要 better-scroll 的 on 方法,返回內(nèi)容滾動時候的 Y軸偏移值。所以在初始化 better-scroll 的時候需要添加一下代碼。對了,別忘了在 data 中添加一個 scrollY,和 currentIndex (用來記錄高亮索引的位置)因為我們需要監(jiān)聽,所以在 data 中添加。
_initSrcoll() {
?this.scroll = new BScroll(this.$refs.listView, {
probeType:3,
click: true
})
?// 監(jiān)聽Y軸偏移的值
this.scroll.on('scroll', (pos) => {
this.scrollY = pos.y
})
}
然后需要計算一下內(nèi)容的高度,添加一個 calculateHeight() 方法,用來計算索引內(nèi)容的高度。
_calculateHeight() {
?this.listHeight = []
const list =this.$refs.listGroup
let height = 0
this.listHeight.push(height)
for (let i = 0; i < list.length; i++) {
let item = list[i]
height += item.clientHeight
this.listHeight.push(height)
}
}
// [0, 760, 1380, 1720, 2340, 2680, 2880, 3220, 3420, 3620, 3960, 4090, 4920, 5190, 5320, 5590, 5790, 5990, 6470, 7090, 7500, 7910, 8110, 8870]
// 得到這樣的值
然后在 watch 中監(jiān)聽 scrollY,看代碼:
watch: {
scrollY (newVal) {
? ?// 向下滑動的時候 newVal 是一個負(fù)數(shù),所以當(dāng) newVal > 0 時,currentIndex 直接為 0
if (newVal > 0) {
this.currentIndex = 0
return
}
// 計算 currentIndex 的值
for(leti= 0;i
let height1 =this.listHeight[i]
let height2 =this.listHeight[i + 1]
if (-newVal >= height1 && -newVal < height2) {
this.currentIndex = i
return
}
}
// 當(dāng)超 -newVal > 最后一個高度的時候
// 因為 this.listHeight 有頭尾,所以需要 - 2
this.currentIndex=this.listHeight.length-2
}
}
得到 currentIndex 的之后,在 html 中使用。
給索引綁定 class --> ?:class="{'current': currentIndex === index}"
最后再處理一下滑動索引的時候改變 currentIndex。
因為代碼可以重復(fù)利用,且需要處理邊界情況,所以就把
this.scroll.scrollToElement(this.$refs.listGroup[index])
重新寫了個函數(shù),來減少代碼量。
// 在 scrollToElement 的時候,改變 scrollY,因為有 watch 所以就會計算出 currentIndex
scrollToElement(index) {
// 處理邊界情況
// 因為 index 通過滑動距離計算出來的
// 所以向上滑超過索引框框的時候就會 < 0,向上就會超過最大值
if (index < 0) {
return
}elseif(index>this.listHeight.length-2) {
index =this.listHeight.length - 2
}
// listHeight 是正的, 所以加個 -
this.scrollY=-this.listHeight[index]
this.scroll.scrollToElement(this.$refs.listGroup[index])
}
lazyload
lazyload 插件也順便說一下哈,增加一下用戶體驗。
順便給大家推薦一個裙,它的前面是 537,中間是631,最后就是 707。想要學(xué)習(xí)前端的小伙伴可以加入我們一起學(xué)習(xí),互相幫助。群里每天晚上都有大神免費直播上課,如果不是想學(xué)習(xí)的小伙伴就不要加啦。(537-631-707)
使用方法
1.先 npm 安裝
2.在 main.js 中 import,然后 Vue.use
importVueLazyloadfrom'vue-lazyload'
Vue.use(VueLazyload, {
loading:require('./common/image/default.jpg')
})
添加一張 loading 圖片,使用 webpack 的 require 獲取圖片。
3.然后在需要使用的時候,把 :src="" 換成 v-lazy="" 就實現(xiàn)了圖片懶加載的功能。