# Hook 函数
又名组合式函数。
# 为什么使用 Hook
在 Vue 中我们一般使用 mixins 来进行代码的复用,mixins 虽然好用,但也有着弊端。
1.弊端一: 会涉及到覆盖的问题。
2.弊端二:隐式传入,变量来源不明确,不利于阅读,使代码变得难以维护。
在 Vue3 中我们可以通过 hook 函数来处理复用代码逻辑的封装提高代码的复用性。
# TS例子
# 封装一个转 base64 的函数
//hook.ts
import {onMounted} from 'vue'
type Option ={
el:string
}
export default function(option:Option):Promise{
return new Promise((resolve)=>{
onMounted(()=>{
let img:HTMlImageElement=document.querySelect(Option.el) as HTMlImageElement
img.onload=()=>{
resolve({
base64:base64(img)
})
}
})
const base64=(el:HTMlImageElement)=>{
const canvas=document.createElement("canvas");
canvas.width = el.width;
canvas.height = el.height;
const ctx = canvas.getContext("2d");
ctx?.drawImage(image, 0, 0, image.width, image.height);
const ext = image.src
.substring(image.src.lastIndexOf(".") + 1)
.toLowerCase();
const dataUrl = canvas.toDataURL("image/" + ext)
const base64 = JSON.parse(JSON.stringify(dataUrl));
return base64
}
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
引入 Hook 函数:
//app.vue
<template>
<div>
<img id='img' width='200' height='200' src='../assets/img.png' />
</div>
</template>
<script setup lang='ts'>
import useBase64 from './hook.ts'
useBase64('#img').then((res)=>{
conaole.log(res)
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# JS例子
# 封装一个鼠标跟踪器
// mouse.js
import { ref, onMounted, onUnmounted } from 'vue'
// 按照惯例,组合式函数名以“use”开头
export function useMouse() {
// 被组合式函数封装和管理的状态
const x = ref(0)
const y = ref(0)
// 组合式函数可以随时更改其状态。
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
// 一个组合式函数也可以挂靠在所属组件的生命周期上
// 来启动和卸载副作用
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
// 通过返回值暴露所管理的状态
return { x, y }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
下面是它在组件中使用的方式:
<script setup>
import { useMouse } from './mouse.js'
const { x, y } = useMouse()
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>
1
2
3
4
5
6
7
2
3
4
5
6
7
# 封装接口请求并处理响应式参数
// fetch.js
import { ref, isRef, unref, watchEffect } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
function doFetch() {
// 在请求之前重设状态...
data.value = null
error.value = null
// unref() 解包可能为 ref 的值
fetch(unref(url))
.then((res) => res.json())
.then((json) => (data.value = json))
.catch((err) => (error.value = err))
}
if (isRef(url)) {
// 若输入的 URL 是一个 ref,那么启动一个响应式的请求
watchEffect(doFetch)
} else {
// 否则只请求一次
// 避免监听器的额外开销
doFetch()
}
return { data, error }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
现在我们在组件里只需要:
<script setup>
import { useFetch } from './fetch.js'
const { data, error } = useFetch('...')
</script>
1
2
3
4
5
2
3
4
5