1、如何理解vue3中的自定义hooks
在Vue 3中,自定义hooks允许开发者封装和重用逻辑代码。自定义hooks是使用Composition API时创建的函数,这些函数可以包含任意的组合逻辑,并且可以在多个组件之间共享。
自定义hooks通常遵循这样的命名约定:以 use
开头,后面跟上hook的名称,这样做可以清晰地表明它是一个自定义的hooks。
2、hooks与utils的区别
相同点:
通过 hooks 和 utils 函数封装, 可以实现组件间共享和复用,提高代码的可重用性和可维护性。
不同点:
01.表现形式不同: hooks 是在 utils 的基础上再包一层组件级别的东西(钩子函数等);utils 一般用于封装相应的逻辑函数,没有组件的东西;
02.数据是否具有响应式: hooks 中如果涉及到 ref,reactive,computed 这些 api 的数据,是具有响应式的;而 utils 只是单纯提取公共方法就不具备响应式;
03.作用范围不同: hooks 封装,可以将组件的状态和生命周期方法提取出来,并在多个组件之间共享和重用;utils 通常是指一些辅助函数或工具方法,用于实现一些常见的操作或提供特定功能。
3、自定义hooks封装规范:
01、具备可复用功能,才需要抽离为 hooks 独立文件
02、函数名/文件名以 use 开头,形如: useXX
03、引用时将响应式变量或者方法显式解构暴露出来;
4、创建自定义hooks
创建自定义hooks非常简单,你只需要定义一个函数,这个函数内部可以包含你需要重用的任何逻辑:
// useCounter.js
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
function increment() {
count.value++;
}
function decrement() {
count.value--;
}
// 返回一个对象,包含响应式状态和函数
return { count, increment, decrement };
}
5、使用自定义hooks
在组件中使用自定义hooks就像使用Vue提供的内置hooks一样:
<template>
<div>
<button @click="decrement">-</button>
<span>{{ count }}</span>
<button @click="increment">+</button>
</div>
</template>
<script setup>
import { useCounter } from './useCounter.js';
const { count, increment, decrement } = useCounter(10);
</script>
6、实际开发中常用的hooks案例
6.1、验证码倒计时
~useCountDown.js
/**
* 验证码倒计时:
* 说明:这个自定义hook可以被导入并在Vue组件中使用,以实现验证码倒计时的功能。通过调
* 用 countDown 函数并传入初始秒数,可以启动倒计时,倒计时的当前秒数将通过 count 响应
* 式引用存储并更新。当倒计时结束时,可以自动执行传入的回调函数。
* @param {Number} second 倒计时秒数
* @return {Number} count 倒计时秒数
* @return {Function} countDown 倒计时函数
* @example
* cosnt { count, countDown } = useCountDown()
* countDown(60)
* <div>{{ count }}</div>
*/
import { ref, onBeforeMount } from 'vue'
export function useCountDown() {
// 存储倒计时的当前秒数
const count = ref(0)
// 设置定时器
const timer = ref(null)
/**
* countDown 函数,它接收两个参数:
* second(可选):倒计时的初始秒数,默认为60。
* ck(可选):倒计时结束时调用的回调函数,默认为空函数。
* @param {*} second
* @param {*} ck
*/
const countDown = (second= 60, ck = () => {}) => {
// 即倒计时未启动或已结束
if (count.value === 0 && timer.value === null) {
ck()
count.value = second
timer.value = setInterval(() => {
count.value--
if (count.value === 0) {
clearInterval(timer.value)
timer.value = null
}
}, 1000)
}
}
// 在组件挂载之前
onBeforeMount(() => {
// timer.value 存在(即倒计时正在运行),就清除定时器
timer.value && clearInterval(timer.value)
})
return {
count,
countDown
}
}
组件内使用:
import { useCountDown } from '../../hooks/useCountDown'
// 1、验证码倒计时hooks
const { count, countDown } = useCountDown()
const sendCode = () => {
console.log('发送了验证码');
}
<!-- 1、验证码倒计时 -->
<h4>验证码倒计时</h4>
<button :disabled="count != 0" class="code-btn" @click="countDown(5, sendCode)">发送验证码</button>
<span>倒计时:{{ count || 0 }}</span>
<br>
6.2、防抖函数
~useDebounce.js
/**
* 防抖
* 说明:防抖是一种限制函数执行频率的技术,确保函数在指定的时间间隔 delay 后执行,
* 如果在该间隔内再次触发,则重新计时。
* @param {Function} fn 需要防抖的函数 delay 防抖时间
* @return {Function} debounce 防抖函数
* @example
* const { debounce } = useDebounce()
* const fn = () => { console.log('防抖' }
* const debounceFn = debounce(fn, 1000)
* debounceFn()
*/
import { ref } from 'vue'
export function useDebounce(fn, delay) {
const debounce = (fn, delay) => {
// 设置定时器
let timer = null
// 返回一个匿名函数
return () => {
if (timer) clearInterval(timer)
// 设置一个新的 setTimeout 定时器,等待 delay 毫秒后执行传入的 fn 函数
timer = setTimeout(() => {
// 确保 fn 函数能够接收到正确的 this 上下文和参数
fn.apply(this, arguments)
}, delay);
}
}
// 用于生成具体的防抖函数
return {
debounce
}
}
组件内使用:
import { useDebounce } from '@/hooks/useDebounce'
// 2、防抖
const { debounce } = useDebounce() // 引入防抖函数
const debouFn = () => {
console.log('防抖——点击了按钮,1秒执行一次');
}
const debounceClick = debounce(debouFn, 1000)
<!-- 2、防抖 -->
<h4>防抖函数</h4>
<button @click="debounceClick">防抖点击</button>
<br>
6.3、节流函数
~useThrottle.js
/**
* 节流
* 说明:节流是一种限制函数执行频率的技术,确保函数在指定的时间间隔 delay 内
* 最多只执行一次,无论触发了多少次。
* @param {Function} fn 需要节流的函数 delay 节流时间
* @return {Function} throttle 节流函数
* @example
* const { throttle } = useThrottle()
* const fn = () => { console.log('节流') }
* const throttleFn = throttle(fn, 1000)
* throttleFn()
* 注意事项:
* timer 变量用于确保在节流的时间间隔 delay 内最多只执行一次函数 fn。
* 使用 apply 方法是为了确保当 fn 被执行时,能够使用调用 throttle 时的 this 上下文和参数。
*/
export function useThrottle(fn, delay) {
const throttle = (fn, delay) => {
let timer = null
// 返回一个匿名函数,该函数将在实际调用节流函数时执行
return function () {
// timer 不存在(即前一个节流操作尚未结束)
if (!timer) {
timer = setTimeout(() => {
// 确保 fn 函数能够接收到正确的 this 上下文和参数
fn.apply(this, arguments)
// 执行完 fn 后,将 timer 设置回null,以便下一次可以再次触发节流
timer = null
}, delay)
}
}
}
return {
throttle
}
}
组件内使用:
import { useThrottle } from '@/hooks/useThrottle'
// 3、节流
const { throttle } = useThrottle() // 引入节流函数throttle
const throFn = () => {
console.log('节流——点击按钮,5秒内只执行一次');
}
const throttleClick = throttle(throFn, 5000)
<!-- 3、节流 -->
<h4>节流函数</h4>
<button @click="throttleClick">节流点击</button>
6.4 XXX (后面遇到需要封装的hooks再更新,请持续关注。)
7、注意事项
- 自定义hooks应该专注于执行特定的任务,避免在一个hooks中做太多事情。
- 保持自定义hooks的命名直观且描述性强,这样其他开发者可以快速理解hooks的用途。
- 由于自定义hooks是函数,它们可以接收参数,这使得它们更加灵活和强大。
自定义hooks是Vue 3 Composition API的强大特性之一,它们提供了一种新的方式来组织和重用代码,使得Vue组件更加简洁和易于管理。