这几天在做商城首页的商品列表,商品卡片的数量很多,如果一次性加载那么多,加载较慢,而且用户体验不好。所以使用鼠标无限滚动加载效果更好。 实现滚动加载的方式有很多,有现成的组件 InfiniteScroll,但是一些非主流浏览器无法触发,还是自己动手写一写吧。
实现滚动加载的核心:滚动条高度 + 浏览器窗口高度 >= 内容高度 - 阈值
document.body.scrollTop
滚动条滚动的距离 (这个有兼容性问题,兼容性写法)let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop
;window.innerHeight
浏览器窗口高度document.body.scrollHeight
内容高度 (兼容性写法)let bodyHeight = document.body.scrollHeight || document.documentElement.scrollHeight
;
- 自定义指令
v-scroll
directives: {
/**
* 滚动加载的自定义指令
*/
scroll: {
bind(el, binding, vnode) {
window.addEventListener('scroll', vnode.context.scrollLoad)
},
unbind(el, binding, vnode) {
window.removeEventListener('scroll', vnode.context.scrollLoad)
}
}
},
methods: {
scrollLoad() {
//滚动条高度(页面被卷去高度)
let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
//文档高度
let bodyHeight = document.body.scrollHeight || document.documentElement.scrollHeight;
// 滚动条高度 + 浏览器高度 >= 文档高度 - 阈值
if (scrollTop + window.innerHeight >= bodyHeight - 300) {
// 判断请求发送标志位,避免重复请求
if (this.loading) return;
// 加载的页码和每次滚动加载的数量,中data中声明
if (this.listIndex * this.PageQty >= this.total) return;
this.listIndex++
// 获取商品数据的异步操作
this.getProductList(this.listIndex)
}
}
}
复制代码
这里需要注意:
因为发送请求和滚动事件的方法定义在了组件的
methods
中,需要拿到Vue实例,但在自定义指令里,不能通过this
拿到Vue实例,而是通过指令钩子函数的第三个参数vnode
的context
属性拿必须要在unbind钩子中解绑滚动加载事件,否则在其他页面也会被触发。
使用时,因为基于文档高度和滚动条高度,绑在哪里无所谓。
<template>
<div id="index" v-scroll>
<ul>
<li v-for="(item, index) in productList" :key="index">
</li>
</ul>
</div>
</template>
复制代码