vue3中Hook使用以及Hook结合自定义指令
作者:白臻
Vue3的自定义的hook
hook是钩子的意思,看到“钩子”是不是就想到了钩子函数?事实上,hooks 还真是函数的一种写法。
vue3 借鉴 reacthooks 开发出了 Composition API ,所以也就意味着 Composition API 也能进行自定义封装 hooks。
vue3 中的 hooks就是函数的一种写法,就是将文件的一些单独功能的js代码进行抽离出来,放到单独的js文件中,或者说是一些可以复用的公共方法/功能。
其实hooks 和 vue2 中的 mixin 有点类似,但是相对 mixins 而言, hooks 更清楚复用功能代码的来源, 更清晰易懂。
Vue3 hook库:hook 官网
手写自定义hook 案例一
1.新建 hooks/iondex.ts 文件
import { onMounted } from "vue" type Options = { el: string } export default function (options: Options): Promise<{ baseUrl: string }> { return new Promise((resolve) => { onMounted(() => { let img: HTMLImageElement = document.querySelector(options.el) as HTMLImageElement; img.onload = () => { resolve({ baseUrl: base64(img) }) } }) const base64 = (el: HTMLImageElement) => { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') canvas.width = el.width; canvas.height = el.height; ctx?.drawImage(el, 0, 0, canvas.width, canvas.height) return canvas.toDataURL('image/png') } }) }
2.在文件中使用
<template> <div> <img id="img" width="300" height="300" src="../../assets/vue.svg" alt="" /> </div> </template> <script setup lang="ts"> import useBase64 from "../hooks/index" useBase64({ el: "img", }).then((res) => { console.log(res.baseUrl) }) </script> <style scoped lang="scss"></style>
3.展示效果 在控制台显示 然后复制 base64码 到浏览器 可显示图片
手写自定义hook 案例二
需求:
实现一个函数同事支持hook 和自定义指令 去监听dom宽高的变化 5w3h 八何分析法
- 1.如何监听dom宽高变化
- 2.如何用vite打包库
- 3.如何发布npm
1.新建工程 V-RESIZE-XM
新建src/index.ts文件
- - 输入 pnpm init 终端命令 生成 package.json 配置文件
- - 输入 tsc --init 终端名称 生成 tsconfig.json 配置文件
- - 新建 vite.config.ts 文件
- - 新建 index.d.ts 文件
- - 安装 两个库 pnpm i vue -D pnpm i vite -D
2.进入 src/index.ts文件中完成hook
ResizeObserver
主要侦听元素宽高的变化MutationObserver
主要侦听子集的变化 还有属性的变化 以及 增删改查interSectionObserver
主要侦听元素是否在视口内
import type { App } from 'vue' function useResize(el: HTMLElement, callback: Function) { let resize = new ResizeObserver((entries) => { callback(entries[0].contentRect) }) resize.observe(el) } // vue 插件 const install = (app: App) => { app.directive('resize', { mounted(el, binding) { useResize(el, binding.value) } }) } useResize.install = install export default useResize
3.打包 成为一个库
在vite.config.ts 文件中配置
import { defineConfig } from 'vite' // umd 支持amd cmd cjs 全局变量模式 export default defineConfig({ build: { lib: { entry: 'src/index.ts', name: 'userResize', }, rollupOptions: { // 确保外部化处理那些你不想打包进库的依赖 external: ['vue'], output: { // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量 globals: { useResize: 'useResize' } } } } })
4.修改package.json 文件
{ "name": "v-resize-xm", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build":"vite build" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "vite": "^5.2.11", "vue": "^3.4.26" } }
5.npm run build 命令后 打包
6. 在 index.d.ts 编写声明文件
declare const useResize: { (el: HTMLElement, callback: Function): void; install: (app: App) => void }; export default useResize
7.准备就绪 发布npm 需要配置 package.json
- 当使用import 、export的时候它会去找对应的module
- 当使用require的时候 它会去找对应的main
- 然后配置files是往 npm 上发布的目录
- 修改版本因为是第一次发布 改成0.0.1
{ "name": "v-resize-xm", "version": "0.0.1", "description": "", "main": "dist/v-resize-xm.umd.js", "module": "dist/v-resize-xm.mjs", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build":"vite" }, "keywords": [], "author": "", "files": [ "dist", "index.d.ts" ], "license": "ISC", "devDependencies": { "vite": "^5.2.11", "vue": "^3.4.26" } }
8.上传npm
如果没有npm 账号
npm adduser
有账号的话 npm login
上传插件 npm publish
9.上传成功后
可以去npm 官网 搜索package.json 定义的 name 名称进行搜索
链接:npm官网地址
10.使用
在项目中安装库
pnpm i v-resize-smy
在文件中引入
一下代码自定义hook 的实例
<template> <div id="resize"> <a href="http://vitejs.dev" rel="external nofollow" rel="external nofollow" target="_blank"> <img src="/vite.svg" class="logo" alt="Vite logo" /> </a> </div> </template> <script setup lang="ts"> import useResize from "v-resize-smy" import { onMounted } from "vue" onMounted(() => { useResize(document.querySelector("#resize") as HTMLElement, (e: any) => { console.log(e) }) }) </script> <style scoped lang="scss"> #resize { border: 1px solid #ccc; resize: both; overflow: hidden; } img { width: 50px; height: 50px; } </style>
11.自定义指令+hook 综合使用案例
在main.ts 文件中注册
import useResize from “v-resize-smy” app.use(useResize)
在文件中使用 示例如下
<template> <div v-resize="resizeWd" id="resize"> <a href="http://vitejs.dev" rel="external nofollow" rel="external nofollow" target="_blank"> <img src="/vite.svg" class="logo" alt="Vite logo" /> </a> </div> </template> <script setup lang="ts"> const resizeWd = (el: any) => { console.log(el) } </script> <style scoped lang="scss"> #resize { border: 1px solid #ccc; resize: both; overflow: hidden; } img { width: 50px; height: 50px; } </style>
hooks 优点
- 1.hooks 作为独立逻辑的组件封装,其内部的属性、函数等和外部组件具有响应式依附的作用。
- 2.自定义 hook 的作用类似于 vue2 中的 mixin 技术,使用方便,易于上手。
- 3.使用 Vue3 的组合 API 封装的可复用,高内聚低耦合。
hooks和utils区别
相同点:
- 通过 hooks 和 utils 函数封装, 可以实现组件间共享和复用,提高代码的可重用性和可维护性。
异同点:
- 表现形式不同:hooks 是在 utils 的基础上再包一层组件级别的东西(钩子函数等);utils一般用于封装相应的逻辑函数,没有组件的东西;
- 数据是否具有响应式:hooks 中如果涉及到 ref,reactive,computed 这些 api 的数据,是具有响应式的;而utils 只是单纯提取公共方法就不具备响应式;
- 作用范围不同:hooks 封装,可以将组件的状态和生命周期方法提取出来,并在多个组件之间共享和重用;utils通常是指一些辅助函数或工具方法,用于实现一些常见的操作或提供特定功能。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。