示例 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>; // 监听变化并保存到 localStorage watchEffect(() => { 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,能显著提升代码质量和开发效率!