這幾天研究項目時,看到了 better-scroll 插件,看着感覺功能挺強,據稱是目前最完善的滾動插件,也就結合着Vue框架學習了起來,自己上手練習總會遇到 better-scroll 已經初始化了, 但是沒法滾動的情況,回過頭看 better-scroll 的官方文檔,找不到答案。感覺其文檔還是過於簡單, 很多需要舉例明確說明的概念都沒有講清楚,和 Vue 的官方文檔相比,確實存在着不小的差距。當然,這里不是說 better-scroll 插件做的不夠好,只是文檔有點簡略了,對新手不太友好。
大家可能已經看過 better-scroll 的官方文檔,下面的這張圖片引自官網,其中 wrapper (綠色的)為父元素,它會有固定的高度,content (黃色的)是父容器的第一個子元素,它的高度會隨着內容的大小而撐高。一旦 content 的高度超過了父容器的高度,我們就可以實現滾動了,這就是 better-scroll 的滾動原理。
本篇教程結合代碼實例,主要針對新手常見的 better-scroll 已經初始化,但依然無法滾動的問題,主要以下有 2 點原因,會結合着實例給大家講解:
1、better-scroll 只處理容器(wrapper)的第一個子元素(content)的滾動,其它的元素都會被忽略。
2、父元素需要有固定的高度,否則無法滾動。
一、使用方法:
1. 安裝:
npm install better-scroll
2. 初始化:(兩種都可以)
mounted() { setTimeout( ()=> { this.scroll = new BScroll(this.$refs.wrapper, {}) }, 20) },
mounted() { this.$nextTick(() => { this.scroll = new Bscroll(this.$refs.wrapper, {}) }) }
這里的 this.$nextTick 和 setTimeout(fn, 20) 都是可以的(20 ms 是一個經驗值,每一個 Tick 約為 17 ms),對用戶體驗而言都是無感知的。
3. 重點:
better-scroll 初始化是針對父容器的第一個子元素。 例如:
<div class="wrapper"> <ul class="content1"> <li>...</li> <li>...</li> ... </ul> <!-- 這里可以放一些其它的 DOM,但不會影響滾動 --> <ul class="content2"> <li>...</li> </ul> </div>
我們進行初始化:
let scroll = new BScroll('.wrapper', {})
此時,.content1 中的內容可以實現滾動,而 .content2 中的內容是不會實現滾動效果的。
也許你會覺得這里很容易理解,不過在實際的項目中,我們可能會遇到無法滾動的情況,其中的問題很有可能出在這里,比如:
<div class="wrapper"> <section v-for="(value, key) in cities" > <p class="title">{{key}}</p> <div class="city-box" v-for="item in value"> <p class="city-name">{{item.name}}</p> </div> </section> </div>
其中的 cities 如下,也就是一個簡單的嵌套循環。
cities: { "A": [{"name": "阿壩"},{"name": "阿克蘇"}, {"name": "阿拉善盟"}, {"name": "阿勒泰"}], "B": [{"name": "北京"}, {"name": "白城"}, {"name": "百色"}, {"name": "白山"}], "C": [{"name": "重慶"}, {"name": "常州"}, {"name": "成都"}, {"name": "滄州"}, {"name": "常德"}], }
此時對 .wrapper 進行初始化:
let scroll = new BScroll('.wrapper', {})
你會發現頁面依然無法滾動,但是.wrapper是父容器, <section></section> 是其第一個子元素,理論上 <section></section> 中的內容應該可以實現滾動效果才對,那么原因在哪里呢?
這里的問題實際就是出在嵌套循環上,可以看到,由於 v-for 的存在,實際上頁面是渲染出了三個 <section></section> ,而 better-scroll 只會對第一個 <section></section> 中的內容實現滾動,當第一個 <section></section> 中的內容高度小於父容器的高度時,頁面是不會滾動的,由此可以解決上述問題,可以在 <section></section> 的外層再加一個 <div></duv> ,將三個 <section></section> 都包裹起來即可。
二、將 better-scroll 封裝成 Vue 組件
1. 新建 BScroll.vue ( 位於:@/components/ ):
<template> <!--滾動組件--> <div class="content-scroll" ref="scrollRef"> <slot></slot> </div> </template>
<script> import BScroll from 'better-scroll' export default { mounted() { // 確保在 Dom 初始化后才執行滾動方法 setTimeout(() => { this._initScroll(); }, 20) }, methods: { _initScroll() { if(!this.$refs.scrollRef) return ;
this.scroll = new BScroll(this.$refs.scrollRef, {}); }, }, } </script>
2. 在父組件中引用,我們將父組件命名為 CityList.vue (位於:@/views 文件夾下),我們模擬一些城市的名稱,將其顯示出來:
<template> <div class="wrapper" ref="wrapper"> <bet-scroll class="content-scroll"> <!-- 引用上一步封裝的better-scroll組件 --> <div> <p v-for="item in cities" :key="item.id" class="city-name"> {{item.name}} </p> </div> </bet-scroll> </div> </template>
<script> import BScroll from '@/components/BScroll.vue'; export default { components: { BetScroll: BScroll }, data() { return { probeType: 3, listenScroll: true, cities: [ {"id": 1,"name": "北京"}, {"id": 3,"name": "上海"}, {"id": 47,"name": "杭州"}, ... ] } }, } </script>
<style> .city-name{ height: 30px; border-bottom: 1px solid #f2f2f2; line-height: 20px; } </style>
此時,我們將頁面運行出來,如下:
結果頁面依然無法滾動! 根據滾動原理,必須給 .content-scroll 添加固定的高度。
添加以下 CSS :
.content-scroll{ height: 300px; overflow: hidden; }
此時,我們發現頁面已經可以滾動,達到了我們想要的效果!
若文章中有不正確的地方,歡迎大家交流指正。
原創不易,若文章幫助到您,您也可以打賞,請俺喝個咖啡哦~