Vue+better-scroll 實現(xiàn)通訊錄字母索引的示例代碼
如??圖,實現(xiàn)一個滾動內(nèi)容區(qū)域,右側(cè)字母滾動索引定位;選擇和拖動字母索引,對應(yīng)內(nèi)容滾動到視窗

環(huán)境準(zhǔn)備:
- 安裝better-scroll npm包
- 安裝 mouseWheel 擴展 BetterScroll 鼠標(biāo)滾輪的能力,開啟鼠標(biāo)滾動(移動端非必須)
npm install @better-scroll/core @better-scroll/mouse-wheel --save
實現(xiàn)步驟:
數(shù)據(jù)結(jié)構(gòu)
- 內(nèi)容區(qū)和索引按下圖數(shù)據(jù)結(jié)構(gòu)處理
export default {
data() {
return {
entityList: [
{
key: 'A',
list: ['氨基酸代謝病', '廣泛性發(fā)育障礙']
},
{
key: 'B',
list: ['巴特綜合征', '包涵體性結(jié)膜炎', '膀胱外翻', '鼻腔結(jié)外型NK/T細(xì)胞淋巴瘤']
},
{
key: 'C',
list: ['C5功能不全綜合征', '腸道蛔蟲癥', '喘息樣支氣管炎']
},
{
key: 'D',
list: ['低氯性氮質(zhì)血癥綜合征', '石棉狀糠疹', 'Dravet綜合征']
}
]
};
}
};
基本HTML
<!-- 內(nèi)容區(qū)域 -->
<!-- 最外層父容器wrapper,固定高度并且overflow:hidden-->
<div class="h-534px flex-1 wrapper overflow-hidden" ref="wrapper">
<!-- content 注意滾動區(qū)域一定是父容器的第一個子元素,當(dāng)高度超出父容器即可滾動 -->
<ul class="content">
<!-- v-for 循環(huán)出列表 -->
<li
v-for="(item, index) in entityList"
:key="index"
class="flex flex-col"
ref="listGroup"
>
<div
class="h-42px leading-42px text-sm font-bold pl-15px w-244px"
>
{{ item.key }}
</div>
<div class="flex flex-col">
<span
class="h-42px leading-42px text-sm pl-15px g-clamp1 w-244px"
v-for="(it, i) in item.list"
:key="i"
>
{{ it }}
</span>
</div>
</li>
</ul>
</div>
<!-- 索引 -->
<ul class="entityList w-15px bg-white">
<!-- v-for 循環(huán)出索引 -->
<li
v-for="(item, index) in entityList"
:key="index"
:data-index="index"
class="w-3 text-4 h-3 mb-1 leading-3 text-center text-gray6"
>
{{ item.key }}
</li>
</ul>
使用better-scroll實現(xiàn)內(nèi)容區(qū)列表的滾動
<script>
//import 引入BScroll
import BScroll from '@better-scroll/core';
import MouseWheel from '@better-scroll/mouse-wheel';
BScroll.use(MouseWheel);
export default {
mounted() {
//dom渲染完畢,初始化better-scroll
this.$nextTick(() => {
this.initBanner();
});
},
methods: {
initBanner() {
if (this.scroll && this.scroll.destroy){
this.scroll.refresh();//當(dāng) DOM 結(jié)構(gòu)發(fā)生變化的時候需重新計算 BetterScroll
this.scroll.destroy();//銷毀 BetterScroll,解綁事件
}
this.scroll = new BScroll('.wrapper', {
scrollY: true,//縱向滾動
click: true,
mouseWheel: true,
disableMouse: false, //啟用鼠標(biāo)拖動
disableTouch: false, //啟用手指觸摸
probeType: 3 //設(shè)置為3,BetterScroll實時派發(fā) scroll 事件
});
}
}
};
</script>
??注意:這里我們在mounted時期,在this.$nextTick 的回調(diào)函數(shù)中初始化 better-scroll 。這時wrapper 的 DOM 已經(jīng)渲染了,我們可以正確計算它以及它內(nèi)層 content 的高度,以確保滾動正常。
給索引添加點擊事件和移動事件實現(xiàn)跳轉(zhuǎn)
<ul class="entityList w-15px bg-white">
<li
v-for="(item, index) in entityList"
:key="index"
:data-index="index"
class="w-3 text-4 h-3 mb-1 leading-3 text-center text-gray6"
@touchstart="onShortcutStart" //點擊事件
@touchmove.stop.prevent="onShortcutMove" //移動事件
>
{{ item.key }}
</li>
</ul>
created() {
// 添加一個 touch 用于記錄移動的屬性
this.touch = {};
this.$nextTick(() => {
this.initBanner();
});
},
methods: {
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);
// 計算最后的位置
let index = this.touch.anchorIndex * 1 + delta;
this.scroll.scrollToElement(this.$refs.listGroup[index]);
}
}
給索引添加高亮
- 在data中定義currentIndex用于索引高亮的判斷,并在html中綁定class
data() {
return {
currentIndex: 0,
entityList: [
{
key: 'A',
list: ['氨基酸代謝病', '廣泛性發(fā)育障礙']
}]
}
}
<ul class="entityList w-15px bg-white">
<li
v-for="(item, index) in entityList"
:key="index"
:data-index="index"
class="w-3 text-4 h-3 mb-1 leading-3 text-center text-gray6"
@touchstart="onShortcutStart"
@touchmove.stop.prevent="onShortcutMove"
:class="{ current: currentIndex === index }"
>
{{ item.key }}
</li>
</ul>
接下來求currentIndex:
- 先通過better-scroll 的on(type, fn, context)方法,監(jiān)聽當(dāng)前實例上的scroll,得到內(nèi)容區(qū)y軸的偏移量
initBanner() {
if (this.scroll && this.scroll.destroy) {
this.scroll.refresh();
this.scroll.destroy();
}
this.scroll = new BScroll('.wrapper', {
scrollY: true,
click: true,
mouseWheel: true,
disableMouse: false, //啟用鼠標(biāo)拖動
disableTouch: false, //啟用手指觸摸
probeType: 3
});
// 監(jiān)聽Y軸偏移的值
this.scroll.on('scroll', pos => {
this.scrollY = pos.y;
});
},
- data中初始化 listHeight ,添加calculateHeight() 方法計算內(nèi)容區(qū)高度
data() {
return {
listHeight: [],
currentIndex: 0,
entityList: [
{
key: 'A',
list: ['氨基酸代謝病', '廣泛性發(fā)育障礙']
}
]
}
}
//計算內(nèi)容區(qū)高度
_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);
}
}
- data中初始化scrollY為-1,在 watch 中監(jiān)聽 scrollY
data() {
return {
scrollY: -1
currentIndex: 0,
listHeight: [],
entityList: [
{
key: 'A',
list: ['氨基酸代謝病', '廣泛性發(fā)育障礙']
}
]
}
}
watch: {
scrollY(newVal) {
// 向下滑動的時候 newVal 是一個負(fù)數(shù),所以當(dāng) newVal > 0 時,currentIndex 直接為 0
if (newVal > 0) {
this.currentIndex = 0;
return;
}
// 計算內(nèi)容區(qū)高度判斷 對應(yīng)索引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;
}
}
// 當(dāng)超 -newVal > 最后一個高度的時候
// 因為 this.listHeight 有頭尾,所以需要 - 2
this.currentIndex = this.listHeight.length - 2;
}
}
這樣就得到了currentIndex 實現(xiàn)索引高亮的特效
全部代碼
<template>
<div>
<!-- 內(nèi)容區(qū)域 -->
<div class="h-534px flex-1 wrapper overflow-hidden" ref="listview">
<ul class="content">
<li
v-for="(item, index) in entityList"
:key="index"
class="flex flex-col"
ref="listGroup"
>
<div class="h-42px leading-42px text-sm font-bold pl-15px w-244px">
{{ item.key }}
</div>
<div class="flex flex-col">
<Link
class="h-42px leading-42px text-sm pl-15px g-clamp1 w-244px"
v-for="(it, i) in item.list"
:key="i"
:to="{
name: 'Yidian',
query: {
title: it
}
}"
>
{{ it }}
</Link>
</div>
</li>
</ul>
</div>
<!-- 索引 -->
<ul class="entityList w-15px bg-white">
<li
v-for="(item, index) in entityList"
:key="index"
:data-index="index"
class="w-3 text-4 h-3 mb-1 leading-3 text-center text-gray6"
@touchstart="onShortcutStart"
@touchmove.stop.prevent="onShortcutMove"
:class="{ current: currentIndex === index }"
>
{{ item.key }}
</li>
</ul>
</div>
</template>
<script>
import BScroll from '@better-scroll/core';
import MouseWheel from '@better-scroll/mouse-wheel';
BScroll.use(MouseWheel);
export default {
data() {
return {
currentIndex: 0,
listHeight: [],
entityList: [
{
key: 'A',
list: ['氨基酸代謝病', '廣泛性發(fā)育障礙']
},
{
key: 'B',
list: ['巴特綜合征', '包涵體性結(jié)膜炎', '膀胱外翻', '鼻腔結(jié)外型NK/T細(xì)胞淋巴瘤']
},
{
key: 'C',
list: ['C5功能不全綜合征', '腸道蛔蟲癥', '喘息樣支氣管炎']
},
{
key: 'D',
list: ['低氯性氮質(zhì)血癥綜合征', '石棉狀糠疹', 'Dravet綜合征']
},
{
key: 'E',
list: ['耳聾', '兒童癲癇', '兒童頭痛', '兒童急性中耳炎']
},
{
key: 'F',
list: ['腹肌缺如綜合征', '肥大性神經(jīng)病', '肺缺如', '樊尚咽峽炎', '腹壁疝']
}
],
scrollY: -1
};
},
mounted() {
this.touch = {};
this.$nextTick(() => {
this.initBanner();
});
},
methods: {
//初始化scroll
initBanner() {
if (this.scroll && this.scroll.destroy) {
this.scroll.refresh();
this.scroll.destroy();
}
this.scroll = new BScroll('.wrapper', {
scrollY: true,
click: true,
mouseWheel: true,
disableMouse: false, //啟用鼠標(biāo)拖動
disableTouch: false, //啟用手指觸摸
probeType: 3
});
this._calculateHeight();
this.scroll.on('scroll', pos => {
console.log(pos.y);
this.scrollY = pos.y;
});
},
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);
// 計算最后的位置
let index = this.touch.anchorIndex * 1 + delta;
//注意這里需要判斷邊界,不然拖動到頂部和底部會報錯
if (index >= 0 && index <= this.entityList.length - 2) {
this.scroll.scrollToElement(this.$refs.listGroup[index]);
}
},
//計算索引內(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);
}
}
},
watch: {
scrollY(newVal) {
// 向下滑動的時候 newVal 是一個負(fù)數(shù),所以當(dāng) 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;
}
}
// 當(dāng)超 -newVal > 最后一個高度的時候
// 因為 this.listHeight 有頭尾,所以需要 - 2
this.currentIndex = this.listHeight.length - 2;
}
}
};
</script>
<style scoped lang="postcss">
.tabActive {
@apply font-bold;
}
.tabActive::after {
content: '';
display: block;
width: 18px;
height: 3px;
background: #00c2b0;
border-radius: 2px;
position: absolute;
bottom: 0;
}
.sortActive {
color: #00c2b0;
}
.select-left {
@apply w-110px;
}
.select-left-item {
@apply pl-15px h-42px text-sm;
}
.entityList {
position: fixed;
right: 8px;
top: 156px;
}
.current {
border-radius: 50%;
background: #00beb0;
color: #fff;
}
.typeAct {
@apply bg-white text-primary;
}
</style>
總結(jié)
- 參考了很多網(wǎng)上的資料,相對于原生實現(xiàn),better-scroll帶來了更大的便利,但是同時也需要我們對better-scroll有一定的了解。
參考文獻(xiàn)
到此這篇關(guān)于Vue+better-scroll 實現(xiàn)通訊錄字母索引的文章就介紹到這了,更多相關(guān)Vue+better-scroll 實現(xiàn)通訊錄字母索引內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue.js分頁組件實現(xiàn):diVuePagination的使用詳解
這篇文章主要介紹了Vue.js分頁組件實現(xiàn):diVuePagination的使用詳解,需要的朋友可以參考下2018-01-01
vue-cli-service build 環(huán)境設(shè)置方式
這篇文章主要介紹了vue-cli-service build 環(huán)境設(shè)置方式,具有很好的參考價值,希望對大家有所幫助。2023-01-01
關(guān)于echarts?清空上一次加載的數(shù)據(jù)問題
這篇文章主要介紹了關(guān)于echarts?清空上一次加載的數(shù)據(jù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
解決vue-router 二級導(dǎo)航默認(rèn)選中某一選項的問題
今天小編就為大家分享一篇解決vue-router 二級導(dǎo)航默認(rèn)選中某一選項的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11
vue中使用vue-router切換頁面時滾動條自動滾動到頂部的方法
這篇文章主要介紹了vue項目中在使用vue-router切換頁面的時候滾動條自動滾動到頂部的實現(xiàn)方法,一般使用Window scrollTo() 方法實現(xiàn),本文給大家簡單介紹了crollTop的使用,需要的朋友可以參考下2017-11-11
Vue使用z-tree處理大數(shù)量的數(shù)據(jù)以及生成樹狀結(jié)構(gòu)
這篇文章主要介紹了Vue使用z-tree處理大數(shù)量的數(shù)據(jù)以及生成樹狀結(jié)構(gòu)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04

