参考一下vantui里的List组件,实现一个印象中的懒加载功能(之所以说是印象中呢主要是vant打不开鸭,全凭记忆中的功能来摸索了);
不是我想重复造轮子,是我想自定义一些些功能。。。
逻辑 主要是监听滚动条 计算设置好的滚动条到底部的高度来异步加载数据,期间异步加载尚未结束时不会重复执行加载操作,所以应该是用了节流。
废话不多说,开始coding
先声明一个组件 就叫他LazyLoad吧
<div class="lazy-load-ctx" ref="scrollRef">
<div class="scroll-ctx" ref="scrollCtxRef">
<slot name="child"></slot>
<div v-show="props.finish" class="not-data">没有更多数据了~</div>
</div>
</div>
ts 这里用了vue3的setup语法糖 定义了传过来的参数以及一个onLoad异步加载数据的方法
const props = defineProps({
finish: {
type: Boolean,
default: false,
},
loading: {
type: Boolean,
default: false,
},
offset: {
type: Number,
default: 300,
},
height: {
type: String,
default: "100%",
},
});
const emit = defineEmits(["onLoad"]);
const scrollRef = ref(null);
const scrollCtxRef = ref(null);
css
.lazy-load-ctx {
height: v-bind("props.height");
overflow-y: auto !important;
.scroll-ctx {
height: auto;
}
.not-data {
text-align: center;
}
}
声明一个节流函数
function throttle<T>(cb: (e: T) => void) {
let state = false;
return (e: T) => {
if (state) return;
cb(e);
state = true;
setTimeout(() => {
state = false;
}, 100);
};
}
页面挂载的时候给容器添加滚动监听事件 首次进来的时候触发onload加载数据的方法;我这里还监听了鼠标滚轮事件,防止数据量小的时候没有撑开容器高度导致无滚动条接连无法触发滚动监听(好像有点多余,Orz)
onMounted(() => {
emit("onLoad");
const dom = scrollRef.value as HTMLDivElement;
dom.addEventListener("scroll", throttle<Event>(onScroll));
dom.addEventListener("wheel", throttle<WheelEvent>(addEventWheel));
});
onScroll函数 获取滚动条到底部的高度
function onScroll(e: Event) {
if (props.finish || props.loading) return;
if (e.target instanceof HTMLDivElement) {
const { scrollHeight, scrollTop, offsetHeight } = e.target;
const scrollBottom = scrollHeight - scrollTop - offsetHeight;
if (scrollBottom < props.offset) {
emit("onLoad");
}
}
}
hasScroll函数 判断页面有无滚动条
function hasScroll() {
return document.body.offsetHeight < (scrollCtxRef.value as HTMLDivElement).offsetHeight;
}
addEventWheel函数 监听鼠标滚轮事件
function addEventWheel(e: WheelEvent) {
const state = hasScroll();
if (!props.finish && !state && e.deltaY > 0 && !props.loading) {
emit("onLoad");
} else return;
}
最后页面卸载的时候记得去清除监听事件 我这里用了节流函数去监听事件,由于用了闭包,每次节流函数都返回了随机的字符,而移除监听事件必须得和添加监听事件的名称一致 导致了现在正常是无法去移除监听事件的,需要对节流函数做一下修改 这里有改造节流函数
onUnmounted(() => {
const dom = scrollRef.value as HTMLDivElement;
});
大致功能就是这样 vue/react拿来改改就能用了
|