0%

解决移动端(已支持 PC)各种滚动场景需求

推荐使用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() {
//在DOM挂载后
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,
});
// 触发scroll(滚动事件)时调用
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可滚动高度区域的计算
    Better-Scroll在决定有多少区域可以滚动时,是根据scrollHeight属性决定的。而scrollHeight属性是根据Better-Scroll中的content中的子组件的高度决定的。
  • 但是,页面中的好多数据(例如图片)都是需要从服务器请求过来的,属于异步操作。也就是说,当Better-Scroll刚开始计算滚动高度时,图片可能还没有请求过来,并没有把图片的高度计算在内。图片请求过来后,可滚动区域高度增大,使得scrollHeight小于真实的滚动区域。

    解决

    思路: 监听每一张图片是否加载完成,只要有一张图片加载完成就执行一次refresh()
  1. 如何监听图片加载完成?
    (1)原生js
    先获取到指定的元素img :img.onload = function() {}
    (2)使用Vue已封装好的方法:@load=”方法”

  2. 在监听到图片加载完成之后,调用scroll中的refresh()(实现非父子组件间的通信)共有两种方法
    (1)使用vuex
    稍后更新
    (2)使用事件总线
    在main.js文件中,通过原型添加$bus
    在这里插入图片描述
    在要监听的组件中,将要监听的事件传递到主页
    在这里插入图片描述
    在主页home.vue组件中监听图片的加载(组件被创建时即开始监听)

1
2
3
4
5
// 监听GoodsItem中的图片是否加载完成
this.$bus.$on("itemImageLoad", () => {
this.$refs.scroll.scroll.refresh();
console.log("---------");
});

解决refresh频繁的问题(防抖)

在解决页面中Better-Scroll可滚动区域的问题时,对每一张图片的加载都进行了监听,当图片很多时,需要多次调用refresh,会增大服务器的压力。
在这里插入图片描述
在规定时间内,如果图片能够加载,就把之前的clear清理掉,重新进行计时;当超过规定时间,就会进行refresh。这样就减少了refresh的次数
注:该文章参考ilovecoding老师课程所写