Home >Web Front-end >JS Tutorial >How to use Vue + better-scroll to implement mobile alphabetical index navigation
This time I will show you how to use Vue better-scroll to implement alphabetical index navigation on the mobile terminal. What are the precautions on using Vue better-scroll to implement alphabetical index navigation on the mobile terminal. The following is a practical case. Let’s take a look.
Demo: list-view, use chrome mobile mode to view. After switching to mobile mode, if you can't slide, refresh it and it will be OK.
Github: Mobile alphabetical index navigation
Rendering
Configuration environment
Because vue-cli and better-scroll are used, vue-cli must be installed first, and then npm install better-scroll.
A brief introduction to better-scroll:
better-scroll is a plug-in that focuses on solving the needs of various scrolling scenarios on the mobile terminal (PC has been supported). Its core is based on the implementation of iscroll. Its API design is basically compatible with iscroll. On the basis of iscroll, it has expanded some features and made some performance optimization.
better-scroll is implemented based on native JS and does not rely on any framework. Its compiled code size is 63kb, 35kb after compression, and only 9kb after gzip. It is a very lightweight JS lib.
In addition to these two, scss and vue-lazyload are also used. Everyone knows the scss preprocessor, and it’s the same with anything else. lazyload implements lazy loading, which can be used without it. The main purpose is to optimize the experience.
The data directly uses the singer list of NetEase Cloud, and if I am lazy, I put it directly in the data.
I won’t post the CSS styles, just look at the source code.
Implement the basic style
Directly use v-for and bilateral nesting to implement the singer list and the index column on the right.
HTML structure:
<ul> <li v-for="group in singers" class="list-group" :key="group.id" ref="listGroup"> <h2 class="list-group-title">{{ group.title }}</h2> <ul> <li v-for="item in group.items" class="list-group-item" :key="item.id"> <img v-lazy="item.avatar" class="avatar"> <span class="name">{{ item.name }}</span> </li> </ul> </li> </ul> <p class="list-shortcut"> <ul> <li v-for="(item, index) in shortcutList" class="item" :data-index="index" :key="item.id" > {{ item }} </li> </ul> </p>
shortcutList is obtained by calculating attributes, just take the first character of title.
shortcutList () { return this.singers.map((group) => { return group.title.substr(0, 1) }) }
Use better-scroll
Use better-scroll to achieve scrolling. By the way, don’t forget to use import when using it.
created () { // 初始化 better-scroll 必须要等 dom 加载完毕 setTimeout(() => { this._initSrcoll() }, 20) }, methods: { _initSrcoll () { console.log('didi') this.scroll = new BScroll(this.$refs.listView, { // 获取 scroll 事件,用来监听。 probeType: 3 }) } }
Use the created method for better-scroll initialization, and use setTimeout because you need to wait until the DOM is loaded. Otherwise, better-scroll will fail to initialize if it cannot obtain the dom.
Write the method here in two methods, so that it will not look messy, just call it directly.
During initialization, two probeTypes are passed in: 3. Explain: when probeType is 3, scroll events are dispatched in real time not only during the screen sliding process, but also during the running of the momentum scrolling animation. If this value is not set, its default value is 0, which means no scroll event is dispatched.
Add click events and move events to the index to achieve jump
First you need to bind a touchstart event to the index (when pressing on the screen Triggered when you lower your finger), just use v-on. Then you need to add a data-index to the index so that you can get the index value, use :data-index="index" .
<p class="list-shortcut"> <ul> <li v-for="(item, index) in shortcutList" class="item" :data-index="index" :key="item.id" @touchstart="onShortcutStart" @touchmove.stop.prevent="onShortcutMove" > {{ item }} </li> </ul> </p>
Bind an onShortcutStart method. Implement the function of clicking the index jump. Then bind an onShortcutMove method to realize sliding jump.
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 方法实现跳转 this.scroll.scrollToElement(this.$refs.listGroup[index]) // 记录一下点击时候的 Y坐标 和 index let firstTouch = e.touches[0].pageY this.touch.y1 = firstTouch this.touch.anchorIndex = index }, onShortcutMove (e) { // 再记录一下移动时候的 Y坐标,然后计算出移动了几个索引 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 偷懒的转化一下 let index = this.touch.anchorIndex * 1 + delta this.scroll.scrollToElement(this.$refs.listGroup[index]) } }
In this way, the index function can be realized.
Of course this won’t satisfy us, right? We need to add cool special effects. For example, index highlighting and so on~~
Mobile content index highlighting
emmm, it’s a bit complicated at this time. But you can understand it if you have patience.
We need the on method of better-scroll to return the Y-axis offset value when the content is scrolled. So you need to add some code when initializing better-scroll. By the way, don’t forget to add a scrollY in data, and currentIndex (used to record the position of the highlighted index) because we need to listen, so add it in data.
_initSrcoll () { this.scroll = new BScroll(this.$refs.listView, { probeType: 3, click: true }) // 监听Y轴偏移的值 this.scroll.on('scroll', (pos) => { this.scrollY = pos.y }) }
Then you need to calculate the height of the content and add a calculateHeight() method to calculate the height of the index content.
_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 中监听 scrollY,看代码:
watch: { scrollY (newVal) { // 向下滑动的时候 newVal 是一个负数,所以当 newVal > 0 时,currentIndex 直接为 0 if (newVal > 0) { this.currentIndex = 0 return } // 计算 currentIndex 的值 for (let i = 0; i < this.listHeight.length - 1; i++) { let height1 = this.listHeight[i] let height2 = this.listHeight[i + 1] if (-newVal >= height1 && -newVal < height2) { this.currentIndex = i return } } // 当超 -newVal > 最后一个高度的时候 // 因为 this.listHeight 有头尾,所以需要 - 2 this.currentIndex = this.listHeight.length - 2 } }
得到 currentIndex 的之后,在 html 中使用。
给索引绑定 class --> :class="{'current': currentIndex === index}"
最后再处理一下滑动索引的时候改变 currentIndex。
因为代码可以重复利用,且需要处理边界情况,所以就把
this.scroll.scrollToElement(this.$refs.listGroup[index])
重新写了个函数,来减少代码量。
// 在 scrollToElement 的时候,改变 scrollY,因为有 watch 所以就会计算出 currentIndex scrollToElement (index) { // 处理边界情况 // 因为 index 通过滑动距离计算出来的 // 所以向上滑超过索引框框的时候就会 < 0,向上就会超过最大值 if (index < 0) { return } else if (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 插件也顺便说一下哈,增加一下用户体验。
使用方法
先 npm 安装
在 main.js 中 import,然后 Vue.use
import VueLazyload from 'vue-lazyload' Vue.use(VueLazyload, { loading: require('./common/image/default.jpg') })
添加一张 loading 图片,使用 webpack 的 require 获取图片。
然后在需要使用的时候,把 :src="" 换成 v-lazy="" 就实现了图片懒加载的功能。
总结
移动端字母索引导航就这么实现啦,感觉还是很有难度的哈(对我来说)。
主要就是使用了 better-scroll 的 on 获取移动偏移值(实现高亮)、scrollToElement 跳转到相应的位置(实现跳转)。以及使用 touch 事件监听触摸,来获取开始的位置,以及滑动距离(计算最后的位置)。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
The above is the detailed content of How to use Vue + better-scroll to implement mobile alphabetical index navigation. For more information, please follow other related articles on the PHP Chinese website!