1:模板
<div
id="list"
class="list"
>
<div
v-for="(msg, index) in listFilter"
:key="index"
class="item"
>{{msg}}</div>
</div>
2:收到数据
props: {
// 数据源
msgList: { type: Array<String>, default: [] },
},
3:处理数据源
setup(props) {
// 列表展示总数
const sum = 16;
// 增减的范围
const addNum = 5;
// 显示数据的区域范围
const listLimit = reactive<{ start: number; end: number }>({
start: 0,
end: sum
});
// 同步数据源
const listSource = ref<Array<string>>([]);
watch(
() => props.msgList,
(val) => {
listSource.value = val;
},
{ immediate: true, deep: true }
);
// 根据范围截取展示的数据
const listFilter = computed(() => listSource.value.slice(listLimit.start, listLimit.end));
// 滑动事件
const setCurrentScrollTop = (e: Event) => {
const element = e.target as HTMLElement;
// clientHeight 视口高度
// scrollHeight整个dom的高度,
// scrollTop当前的滑动高度:最大scrollHeight-clientHeight
const { scrollTop, scrollHeight, clientHeight } = element;
// 下滑处理
if (scrollTop > scrollHeight - clientHeight - 20) {
if (listLimit.end < props.msgList.length) {
// 不能超过长度
listLimit.end += addNum;
listLimit.start += addNum;
// 下滑到20时,触发滑动事件,还需反弹上来,继续触发事件
element.scrollTo(0, scrollHeight - clientHeight - 30);
}
}
// 上滑处理
if (scrollTop < 20) {
if (listLimit.start > 0) {
listLimit.end -= addNum;
// 处理边界
listLimit.start = listLimit.start >= addNum ? listLimit.start - addNum : 0;
element.scrollTo(0, 30);
}
}
};
onMounted(() => {
const element = document.getElementById('list') as HTMLElement;
element?.addEventListener('scroll', setCurrentScrollTop);
});
onUnmounted(() => {
const element = document.getElementById('list') as HTMLElement;
element?.removeEventListener('scroll', setCurrentScrollTop);
});
return { listFilter };
}