共计 4358 个字符,预计需要花费 11 分钟才能阅读完成。
Vue3 的自定义的 hook
hook 是钩子的意思,看到“钩子”是不是就想到了钩子函数?事实上,hooks 还真是函数的一种写法。vue3 借鉴 react
hooks 开发出了 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
- 新建工程 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
- 进入 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)
}
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'
export default defineConfig({
build: {
lib: {
entry: 'src/index.ts',
name: 'userResize',
},
rollupOptions: {
external: ['vue'],
output: {
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
- 准备就绪 发布 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"
}
}
3. 上传 npm
- 如果没有 npm 账号
1.npm adduser- 有账号的话 npm login
- 上传插件 npm publish
4. 上传成功后
可以去 npm 官网 搜索 package.json 定义的 name 名称进行搜索
链接: npm 官网地址
5. 使用
1. 在项目中安装库
pnpm i v-resize-smy
2. 在文件中引入
3. 一下代码自定义 hook 的实例
template>
div id="resize">
a href="http://vitejs.dev" 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>
6. 自定义指令 +hook 综合使用案例
- 在 main.ts 文件中注册
import useResize from“v-resize-smy”
app.use(useResize)- 在文件中使用 示例如下
template>
div v-resize="resizeWd" id="resize">
a href="http://vitejs.dev" 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
通常是指一些辅助函数或工具方法,用于实现一些常见的操作或提供特定功能。
原文地址: vue3 中 Hook 详解 Hook 结合自定义指令