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 缩放(scale)大屏适配hooks的封装

~useSelfAdaption.js

/**
 * 缩放(scale)的方式是一种简单直接的大屏适配方案,其主要思路是通过
 * 改变整个页面的缩放比例来适应不同分辨率的屏幕。这种方案的核心在于将
 * 页面整体进行缩放,以保持页面布局的完整性和一致性。
 * 
 * 缩放(Scale)适配方案思路:
 *      获取屏幕尺寸: 首先,通过JavaScript获取当前设备屏幕的宽度(或高度)。
 *      计算缩放比例: 然后,将获取到的屏幕尺寸与设计稿的基准尺寸进行比较,计算出缩放比例。
 *      应用缩放: 最后,将计算出的缩放比例应用到整个页面上,从而实现页面的缩放适配。
 * 
 * @date 2024-6-3
 * @return {Number} scale 组件可以使用scale来响应屏幕尺寸的变化
 * @example
 * const { scale } = useSelfAdaption()
 * <div :style="{ transform: `scale(${scale})` }">
 *      <!-- Your content here -->
 * </div>
 */

import { ref, onMounted, onUnmounted } from 'vue'

export function useSelfAdaption() {
    const scale = ref(1)

    const setScale = () => {
        const screenWidth = window.innerWidth
        // 设计稿基准宽度
        const baseWidth = 750  //750, 1190, 1920, 根据实际情况设定
        // 计算当前屏幕宽度与基准宽度的比例,并赋值给scale
        scale.value = screenWidth/baseWidth
        console.log('cale:', scale.value);
        // 设置body的CSS变换属性,根据scale的值进行缩放
        document.body.style.transform = `scale(${scale.value})`
    }
    onMounted(() => {
        // 初次挂载时调用setScale函数,以确保页面按照当前屏幕尺寸正确缩放
        setScale()
        // 当窗口大小改变时,触发setScale函数。
        window.addEventListener('resize', setScale)
    })
    onUnmounted(() => {
        // 移除之前添加的resize事件监听器,避免内存泄漏。
        window.removeEventListener('resize', setScale)
    })

    return {
        scale
    }
}

组件内使用:

import { useSelfAdaption } from '../../hooks/useSelfAdaption'   // 引入自适应hooks

// 5、自适应
/**
 * <div :style="{ transform: `scale(${scale})` }"></div>
 */
const { scale } = useSelfAdaption()
<template>
  <!-- 5、缩放(scale)屏幕适配  :style="{ transform: `scale(${scale})` }" -->
  <div class="container" :style="{ transform: `scale(${scale})` }">
        <!-- Your template content -->
  </div>
</template>

 6.5 XXX (后面遇到需要封装的hooks再更新,请持续关注。)

 7、注意事项

  • 自定义hooks应该专注于执行特定的任务,避免在一个hooks中做太多事情。
  • 保持自定义hooks的命名直观且描述性强,这样其他开发者可以快速理解hooks的用途。
  • 由于自定义hooks是函数,它们可以接收参数,这使得它们更加灵活和强大。

自定义hooks是Vue 3 Composition API的强大特性之一,它们提供了一种新的方式来组织和重用代码,使得Vue组件更加简洁和易于管理。

GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐