Appearance
组合式函数
组合式函数又叫做自定义 hook(学过 React Hooks 的同学不要笑~),它可以方便我们实现 SFC 组件之间的有状态逻辑的封装和共享。例如,项目的多个 SFC 都需要获取鼠标在网页上的坐标,为了实现“鼠标位置”逻辑的复用,我们可以把相关的代码封装成名为 useMouse
的组合式函数,并在需要的时候直接复用此函数即可得到鼠标的位置。
🚨 注意 🚨
组合式函数必须以 use
开头!
封装鼠标跟踪器
在 SFC 中实现鼠标跟踪器
vue
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const x = ref(0)
const y = ref(0)
const update = (e) => {
x.value = e.pageX
y.value = e.pageY
}
// 在组件挂载和卸载时,绑定和移除 window 对象的 mousemove 事件监听程序
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
</script>
<template>
<p>鼠标的位置 x: {{ x }},y: {{ y }}</p>
</template>
把鼠标跟踪器封装为组合式函数
为了实现鼠标跟踪器逻辑代码的复用,我们可以把与之有关的状态逻辑封装到独立的 js 模块中。在 src/
下新建 hooks/
文件夹,并在其下新建 mouse.js
的模块:
js
// 在头部区域导入需要用到的组合式 API
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() {
const x = ref(0)
const y = ref(0)
const update = (e) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
// 向外暴露数据
return { x, y }
}
然后,在需要用到鼠标位置的组件中,直接导入自定义的 useMouse
hook 并使用即可:
vue
<script setup>
import { useMouse } from '../hooks/mouse.js'
const { x, y } = useMouse()
</script>
<template>
<p>鼠标的位置 x: {{ x }},y: {{ y }}</p>
</template>
把事件监听器封装为组合式函数
组合式函数可以嵌套使用。例如:把 mousemove
事件监听的绑定和移除的代码,也封装为自定义的组合式函数:
js
// 把事件绑定和移除的过程,封装为自定义 hook
export function useEvent(target, eventName, eventHandler) {
onMounted(() => target.addEventListener(eventName, eventHandler))
onUnmounted(() => target.removeEventListener(eventName, eventHandler))
}
然后,在 useMouse
中可以复用 useEvent
函数:
js
export function useMouse() {
const x = ref(0)
const y = ref(0)
const update = (e) => {
x.value = e.pageX
y.value = e.pageY
}
// 调用自定义 hook,在组件挂载和卸载后,自动绑定和移除“指定的”事件监听程序
useEvent(window, 'mousemove', update)
return { x, y }
}
封装秒数倒计时
使用倒计时的自定义 hook:
vue
<script setup>
import { useCountDown } from '../hooks/countDown.js'
const { count, isOver } = useCountDown(5, () => {
console.log('基于路由 API 自动跳转到首页')
})
</script>
<template>
<!-- 场景1:倒计时结束自动跳转 -->
<h1>{{ count }} 秒后自动跳转</h1>
<!-- 场景2:倒计时结束启用按钮 -->
<button :disabled="!isOver">按钮</button>
</template>
在 src/hooks/
目录下新建 countDown.js
模块:
js
import { ref, onMounted, onUnmounted } from 'vue'
export function useCountDown(initialCount, callback) {
const count = ref(initialCount)
const isOver = ref(false)
let timerId
// 组件挂载完成后,自动开启定时器
onMounted(() => {
timerId = setInterval(() => {
count.value--
if (count.value === 0) {
// 定时器归零后,清除定时器、修改 isOver 状态、执行用户传入的回调
clearInterval(timerId)
isOver.value = true
callback?.()
}
}, 1000)
})
// 组件被卸载后,自动清除定时器
onUnmounted(() => {
clearInterval(timerId)
})
return { count, isOver }
}