这几天在做商城首页的商品列表,商品卡片的数量很多,如果一次性加载那么多,加载较慢,而且用户体验不好。所以使用鼠标无限滚动加载效果更好。 实现滚动加载的方式有很多,有现成的组件 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>复制代码