示例 1: 防抖 Hook(useDebounce
)
typescript
// hooks/useDebounce.ts import { ref, watch, onUnmounted, type WatchSource } from 'vue';/*** 防抖 Hook* @param source 监听的响应式数据源* @param callback 防抖后执行的回调函数* @param delay 防抖延迟时间(毫秒,默认 300ms)*/ export function useDebounce<T>(source: WatchSource<T>,callback: (value: T) => void,delay: number = 300 ) {let timeoutId: number | null = null;// 监听数据源变化watch(source, (newValue) => {// 清除之前的定时器if (timeoutId) {clearTimeout(timeoutId);}// 设置新的定时器timeoutId = setTimeout(() => {callback(newValue);}, delay);});// 组件卸载时清除定时器onUnmounted(() => {if (timeoutId) {clearTimeout(timeoutId);}}); }// 组件中使用示例: // const searchQuery = ref(''); // useDebounce(searchQuery, (value) => { // console.log('防抖后的搜索值:', value); // });
示例 2: 本地存储 Hook(useLocalStorage
)
typescript
// hooks/useLocalStorage.ts import { ref, watchEffect, type Ref } from 'vue';/*** 本地存储 Hook* @param key 存储的键名* @param defaultValue 默认值* @returns 返回响应式变量和更新函数*/ export function useLocalStorage<T>(key: string,defaultValue: T ): [Ref<T>, (value: T) => void] {// 从 localStorage 读取初始值const storedValue = localStorage.getItem(key);const value = ref<T>(storedValue ? JSON.parse(storedValue) : defaultValue) as Ref<T>;// 监听变化并保存到 localStoragewatchEffect(() => {localStorage.setItem(key, JSON.stringify(value.value));});// 提供更新函数(可选,直接修改 value 也有效)const updateValue = (newValue: T) => {value.value = newValue;};return [value, updateValue]; }// 组件中使用示例: // const [theme, setTheme] = useLocalStorage<'light' | 'dark'>('theme', 'light');
示例 3: 网络请求 Hook(useFetch
)
typescript
// hooks/useFetch.ts import { ref, type Ref } from 'vue';interface UseFetchReturn<T> {data: Ref<T | null>;error: Ref<Error | null>;loading: Ref<boolean>;execute: () => Promise<void>; }/*** 网络请求 Hook* @param url 请求地址* @param options 请求配置(可选)*/ export function useFetch<T = unknown>(url: string,options?: RequestInit ): UseFetchReturn<T> {const data = ref<T | null>(null);const error = ref<Error | null>(null);const loading = ref(false);// 执行请求的函数const execute = async () => {loading.value = true;try {const response = await fetch(url, options);if (!response.ok) {throw new Error(`HTTP error! status: ${response.status}`);}data.value = await response.json();error.value = null;} catch (err) {error.value = err as Error;data.value = null;} finally {loading.value = false;}};return { data, error, loading, execute }; }// 组件中使用示例: // const { data, error, loading, execute } = useFetch<User[]>('/api/users'); // execute(); // 手动触发请求
示例 4: 倒计时 Hook(useCountdown
)
typescript
// hooks/useCountdown.ts import { ref, onUnmounted } from 'vue';/*** 倒计时 Hook* @param seconds 倒计时总秒数* @returns 剩余时间(秒)和开始/重置函数*/ export function useCountdown(seconds: number) {const count = ref(seconds);let timer: number | null = null;// 开始/重置倒计时const start = () => {reset(); // 重置倒计时timer = setInterval(() => {if (count.value > 0) {count.value--;} else {clearInterval(timer!);}}, 1000);};// 重置倒计时const reset = () => {if (timer) {clearInterval(timer);timer = null;}count.value = seconds;};// 组件卸载时清除定时器onUnmounted(reset);return { count, start, reset }; }// 组件中使用示例: // const { count, start } = useCountdown(60); // start(); // 开始倒计时
示例 5: 事件监听 Hook(useEventListener
)
typescript
// hooks/useEventListener.ts import { onMounted, onUnmounted } from 'vue';type EventTarget = Window | Document | HTMLElement;/*** 事件监听 Hook* @param target 目标元素(默认 window)* @param event 事件名称* @param listener 事件回调*/ export function useEventListener(event: string,listener: EventListener,target: EventTarget = window ) {// 挂载时添加监听onMounted(() => {target.addEventListener(event, listener);});// 卸载时移除监听onUnmounted(() => {target.removeEventListener(event, listener);}); }// 组件中使用示例: // useEventListener('click', (e) => { // console.log('全局点击事件', e); // });
最佳实践建议:
-
类型安全:
-
使用 TypeScript 接口 (
interface
) 明确函数参数和返回值类型。 -
用泛型 (
<T>
) 处理动态数据类型(如useFetch
中的响应数据)。
-
-
响应式处理:
-
优先使用
ref
替代reactive
(更适合类型推导)。 -
使用
watch
或watchEffect
处理副作用。
-
-
资源清理:
-
在
onUnmounted
中清除定时器、事件监听等资源。
-
-
组合复用:
-
多个简单 Hook 可以组合成复杂逻辑(如
useCountdown
+useEventListener
)。
-
-
推荐工具库:
-
VueUse 提供了大量高质量的类型安全 Hooks。
-
通过这些示例,你可以逐步掌握如何编写类型安全、可复用的 Vue3 Hooks。实际开发中,根据需求灵活组合这些基础 Hooks,能显著提升代码质量和开发效率!