Vue3+Ts封装下拉懒加载自定义指令

文件夹目录如下:

使用方式:

<template>
    <div
	    class="time-line"
	    v-infinite-scroll="{
	        loadMore: loadMoreItems,
		    threshold: 100 // 当滚动到距离底部 100 像素时触发加载
	    }"
    >	
    </div>
</template>

<script lang="ts" setup>
// 下拉懒加载加载数据
const loadMoreItems = () => {
	console.log("下拉懒加载");
	return new Promise(resolve => {
		setTimeout(() => {
			timeLineList.value.push(...new Array(10).fill(null).map(() => Math.random() * 99999999));
			resolve(true);
		}, 1000);
	});
};
</script>

infiniteScroll.ts代码如下:

/**
 * v-infiniteScroll
 * 下拉懒加载
 */
import type { Directive, DirectiveBinding } from "vue";

// 定义一个接口来描述绑定值的类型
interface InfiniteScrollBindingValue {
	threshold?: number;
	loadMore: () => Promise<void>;
}

// 防抖函数
function debounce<T extends (...args: any[]) => void>(func: T, wait: number) {
	let timeout: ReturnType<typeof setTimeout> | undefined;
	return function (this: any, ...args: Parameters<T>) {
		if (timeout) {
			clearTimeout(timeout);
		}
		timeout = setTimeout(() => func.apply(this, args), wait);
	};
}

const infiniteScroll: Directive = {
	mounted(el: HTMLElement, binding: DirectiveBinding<InfiniteScrollBindingValue>) {
		let isLoading = false;
		const threshold = binding.value.threshold || 0;

		const handler = debounce(() => {
			if (isLoading) return;

			const scrollTop = el.scrollTop;
			const scrollHeight = el.scrollHeight;
			const clientHeight = el.clientHeight;
			const scrollBottom = scrollHeight - (scrollTop + clientHeight);

			if (scrollBottom <= threshold) {
				isLoading = true;
				binding.value.loadMore().finally(() => {
					isLoading = false;
				});
			}
		}, 200); // 200ms 防抖时间,可以根据需求调整

		el.addEventListener("scroll", handler);

		// 在 directive 的 `binding` 上保存 `handler` 以便后续访问
		(el as any).__infiniteScrollHandler__ = handler;
	},
	beforeUnmount(el: HTMLElement) {
		// 组件销毁时移除事件监听
		const handler = (el as any).__infiniteScrollHandler__;
		if (handler) {
			el.removeEventListener("scroll", handler);
		}
	}
};

export default infiniteScroll;

index.ts文件如下:

import { App } from "vue";
import infiniteScroll from "./modules/infiniteScroll";

const directivesList: any = {
	infiniteScroll
};

const directives = {
	install: function (app: App<Element>) {
		Object.keys(directivesList).forEach(key => {
			// 注册所有自定义指令
			app.directive(key, directivesList[key]);
		});
	}
};

export default directives;

在main.ts中注册:

import { createApp } from "vue";
import App from "./App.vue";
import directives from "@/directives/index";

const app = createApp(App);
app..use(directives).mount("#app");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值