推荐使用better-scroll插件。本篇博客中的代码是vue与better-scroll的使用
介绍
它的核心是借鉴的 iscroll 的实现,它的 API 设计基本兼容 iscroll,在 iscroll 的基础上又扩展了一些 feature 以及做了一些性能优化。BetterScroll 是使用原生JS实现的。
主要实现的功能:在滚动时,实现顺滑滚动以及弹簧效果(如果使用原生的滚动会出现卡顿的情况)
起步
BetterScroll 提供了一个类,实例化的第一个参数是一个原生的 DOM 对象。当然,如果传递的是一个字符串,BetterScroll 内部会尝试调用 querySelector 去获取这个 DOM 对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <template> <div class="wrap"> <div class="content"> <ul> <li>滚动1</li> <li>滚动2</li> <li>滚动3</li> <li>滚动4</li> <li>滚动5</li> <li>滚动6</li> <!--滚动的元素内容--> </ul> </div> </div> </template>
<script>
import BScroll from "@better-scroll/core"; export default { name: "Category", data() { return { scroll: null }; }, mounted() { this.scroll = new BScroll(document.querySelector(".wrap")); } }; </script>
<style scoped> .wrap { //必须设置wrap的高度 height: 100px; overflow: hidden; } </style>
|
注意:
- BetterScroll 只处理容器(wrapper)的第一个子元素(content)的滚动,其它的元素都会被忽略。
- 父盒子(相当于上面代码的.wrap)必须设置高度才有用
监听滚动位置
默认情况下BScroll不能实时监听滚动位置,需要对probeType进行设置(默认为0)
probeType的值:
0,1:都不侦测实时的位置
2:在手指/鼠标滚动的过程中侦测,手指离开后的的惯性滚动过程中不侦测
3:只要是页面滚动,都侦测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <script> import BScroll from "@better-scroll/core"; export default { name: "Category", data() { return { scroll: null, }; }, mounted() { this.scroll = new BScroll(document.querySelector(".wrap"), { probeType: 3, }); this.scroll.on("scroll", (position) => { console.log(position); }); }, }; </script>
|
侦测上拉加载更多
安装pullup插件
1
| npm install @better-scroll/pull-up@next --save
|
使用
1 2 3 4
| import BScroll from '@better-scroll/core' import Pullup from '@better-scroll/pull-up'
BScroll.use(Pullup)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| export default { name: "Category", data() { return { scroll: null }; }, mounted() { this.scroll = new BScroll(document.querySelector(".wrap"), { probeType: 3, pullUpLoad: true }); this.scroll.on("pullingUp", () => { console.log("上拉加载更多"); }); } };
|
封装
为了减少对BetterScroll的依赖程度,可以选择对BetterScroll的使用封装为一个组件,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| <template> <div class="wrap" ref="wrap"> <div class="content"> <slot></slot> </div> </div> </template> <script> import BScroll from "@better-scroll/core"; import pullup from "@better-scroll/pull-up"; BScroll.use(pullup); export default { name: "Scroll", data() { return { scroll: null, }; }, props: { probeType: { type: Number, default: 0, }, pullUpLoad: { type: Boolean, default: false, }, }, mounted() { this.scroll = new BScroll(this.$refs.wrap, { probeType: this.probeType, pullUpLoad: this.pullUpLoad, click: true, }); this.scroll.on("scroll", (position) => { this.$emit("scroll", position); }); this.scroll.on("pullingUp", () => { this.$emit("pullingUp"); }); }, }; </script> <style scoped> </style>>
|
使用时,将以上封装好的组件引入,并挂载到componens下
注意:ref绑定在组件和绑定在元素上的区别
ref如果绑定在组件上,那么通过this.$refs.refname拿到的就是一个组件对象
ref如果绑定在普通的元素上,那么通过this.$refs.refname拿到的是一个元素对象
用过ref属性获取元素的原因:当组件被使用后。页面中可能有多个同名的class,这样获取到的元素可能不是我们想要的,通过ref就可以解决这个问题
出现问题的原因
- Better-Scroll可滚动高度区域的计算
Better-Scroll在决定有多少区域可以滚动时,是根据scrollHeight属性决定的。而scrollHeight属性是根据Better-Scroll中的content中的子组件的高度决定的。
- 但是,页面中的好多数据(例如图片)都是需要从服务器请求过来的,属于异步操作。也就是说,当Better-Scroll刚开始计算滚动高度时,图片可能还没有请求过来,并没有把图片的高度计算在内。图片请求过来后,可滚动区域高度增大,使得scrollHeight小于真实的滚动区域。
解决
思路: 监听每一张图片是否加载完成,只要有一张图片加载完成就执行一次refresh()
如何监听图片加载完成?
(1)原生js
先获取到指定的元素img :img.onload = function() {}
(2)使用Vue已封装好的方法:@load=”方法”
在监听到图片加载完成之后,调用scroll中的refresh()(实现非父子组件间的通信)共有两种方法
(1)使用vuex
稍后更新
(2)使用事件总线
在main.js文件中,通过原型添加$bus
在要监听的组件中,将要监听的事件传递到主页
在主页home.vue组件中监听图片的加载(组件被创建时即开始监听)
1 2 3 4 5
| this.$bus.$on("itemImageLoad", () => { this.$refs.scroll.scroll.refresh(); console.log("---------"); });
|
解决refresh频繁的问题(防抖)
在解决页面中Better-Scroll可滚动区域的问题时,对每一张图片的加载都进行了监听,当图片很多时,需要多次调用refresh,会增大服务器的压力。
在规定时间内,如果图片能够加载,就把之前的clear清理掉,重新进行计时;当超过规定时间,就会进行refresh。这样就减少了refresh的次数
注:该文章参考ilovecoding老师课程所写