Vue + better-scroll 實現(xiàn)移動端字母索引導(dǎo)航

效果圖:

配置環(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)了圖片懶加載的功能。

          ?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
          【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
          平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

          相關(guān)閱讀更多精彩內(nèi)容

          友情鏈接更多精彩內(nèi)容