Appearance
自定义 Hooks
在 Vue3 的组合式 API 中,自定义 Hooks 是一种非常强大的特性,它允许我们封装和复用逻辑代码,提高代码的可维护性和可复用性。
什么是自定义 Hooks?
自定义 Hooks 是使用组合式 API 创建的可复用函数,它可以封装任何逻辑,包括响应式数据、生命周期钩子、副作用等。
自定义 Hooks 的命名规范
- 通常以
use开头,如useCounter、useApi等 - 函数名使用驼峰命名法
- 文件名通常与函数名相同
基本用法
创建自定义 Hook
javascript
// hooks/useCounter.js
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
function decrement() {
count.value--
}
function reset() {
count.value = initialValue
}
return {
count,
doubleCount,
increment,
decrement,
reset
}
}使用自定义 Hook
vue
<script setup>
import { useCounter } from './hooks/useCounter'
// 使用自定义 Hook
const { count, doubleCount, increment, decrement, reset } = useCounter(10)
</script>
<template>
<div>
<p>当前计数: {{ count }}</p>
<p>双倍计数: {{ doubleCount }}</p>
<button @click="increment">增加</button>
<button @click="decrement">减少</button>
<button @click="reset">重置</button>
</div>
</template>实战示例
1. 封装 API 请求
javascript
// hooks/useApi.js
import { ref, onUnmounted } from 'vue'
export function useApi(url) {
const data = ref(null)
const loading = ref(false)
const error = ref(null)
let controller = null
async function fetchData() {
loading.value = true
error.value = null
try {
controller = new AbortController()
const response = await fetch(url, {
signal: controller.signal
})
if (!response.ok) {
throw new Error('请求失败')
}
data.value = await response.json()
} catch (err) {
if (err.name !== 'AbortError') {
error.value = err.message
}
} finally {
loading.value = false
}
}
function cancel() {
if (controller) {
controller.abort()
}
}
// 组件卸载时取消请求
onUnmounted(() => {
cancel()
})
return {
data,
loading,
error,
fetchData,
cancel
}
}使用示例:
vue
<script setup>
import { useApi } from './hooks/useApi'
const { data, loading, error, fetchData } = useApi('https://api.example.com/data')
// 组件挂载时获取数据
fetchData()
</script>
<template>
<div>
<div v-if="loading">加载中...</div>
<div v-else-if="error">{{ error }}</div>
<div v-else-if="data">
<pre>{{ JSON.stringify(data, null, 2) }}</pre>
</div>
</div>
</template>2. 封装本地存储
javascript
// hooks/useLocalStorage.js
import { ref, watch } from 'vue'
export function useLocalStorage(key, initialValue) {
// 从本地存储中获取初始值
const storedValue = localStorage.getItem(key)
const value = ref(storedValue ? JSON.parse(storedValue) : initialValue)
// 监听值的变化,同步到本地存储
watch(value, (newValue) => {
localStorage.setItem(key, JSON.stringify(newValue))
}, { deep: true })
return value
}使用示例:
vue
<script setup>
import { useLocalStorage } from './hooks/useLocalStorage'
// 使用本地存储
const userPreferences = useLocalStorage('userPreferences', {
theme: 'light',
fontSize: 16
})
function toggleTheme() {
userPreferences.value.theme = userPreferences.value.theme === 'light' ? 'dark' : 'light'
}
</script>
<template>
<div :class="userPreferences.theme">
<p>当前主题: {{ userPreferences.theme }}</p>
<p>字体大小: {{ userPreferences.fontSize }}px</p>
<button @click="toggleTheme">切换主题</button>
</div>
</template>
<style>
.light {
background-color: #fff;
color: #333;
}
.dark {
background-color: #333;
color: #fff;
}
</style>3. 封装鼠标位置
javascript
// hooks/useMouse.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
function updateMousePosition(event) {
x.value = event.clientX
y.value = event.clientY
}
onMounted(() => {
window.addEventListener('mousemove', updateMousePosition)
})
onUnmounted(() => {
window.removeEventListener('mousemove', updateMousePosition)
})
return { x, y }
}使用示例:
vue
<script setup>
import { useMouse } from './hooks/useMouse'
const { x, y } = useMouse()
</script>
<template>
<div>
<p>鼠标位置: ({{ x }}, {{ y }})</p>
</div>
</template>自定义 Hooks 的优势
- 代码复用:将重复的逻辑封装到一个函数中,提高代码的可复用性
- 逻辑清晰:将相关的逻辑组织在一起,提高代码的可读性和可维护性
- 关注点分离:将业务逻辑与 UI 逻辑分离,使组件更加简洁
- 类型安全:在 TypeScript 中可以为自定义 Hooks 添加类型定义,提高代码的类型安全性
最佳实践
- 单一职责:每个自定义 Hook 应该只负责一个功能
- 命名规范:使用
use前缀,清晰表达 Hook 的用途 - 返回值:返回与 Hook 功能相关的响应式数据和方法
- 清理副作用:在 Hook 中使用
onUnmounted等生命周期钩子清理副作用 - 文档:为复杂的自定义 Hook 添加适当的文档说明
通过自定义 Hooks,我们可以更好地组织和复用代码,提高开发效率和代码质量。
