前言
Hooks 在前端领域没有明确定义,一般指JS callback
、事件驱动,集成定义一些可复用的方法。
Vue3 官方文档中没有对 Hooks
做任何定义,但是在Vue应用的概念中,“组合式函数” (Composables
) 是一个利用 Vue 组合式 API 来封装和复用有状态逻辑的函数”。
一些可复用的方法像钩子一样挂着,可以随时被引入和调用以实现高内聚低耦合的目标,应该都能算是 Hook
;
Vue3 中自定义Hook
以函数形式抽离一些可复用的方法像钩子一样挂着,随时可以引入和调用,实现高内聚低耦合的目标;
1. 将可复用功能抽离为外部JS文件
2. 函数名/文件名以use开头,形如:useXX
3. 引用时将响应式变量或者方法显式解构暴露出来如:const {nameRef,Fn} = useXX()
(在setup函数解构出自定义hooks的变量和方法)
实例1
实现一个实时获取鼠标点击时坐标
(x,y)
的Hook
-
定义 usePrint hook
// src/hooks/usePrint.ts
import { onBeforeMount, onUnmounted, reactive } from "vue";
export function usePrint() {
const state = reactive({
x: 0,
y: 0,
});
function print(event: MouseEvent) {
state.x = event.pageX;
state.y = event.pageY;
}
onBeforeMount(() => {
window.addEventListener("click", print);
});
onUnmounted(() => {
window.removeEventListener("click", print);
});
return state;
}
-
组件中应用 usePrint hook
// src/views/about.vue
<template>
<p>点击时的坐标 x:{{ mes.x }} y:{{ mes.y }}</p>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { usePrint } from "@/hooks/usePrint.ts";
export default defineComponent({
setup() {
const mes = usePrint();
return {
mes,
};
},
});
</script>
实例2
简单的加减法计算,将加法和减法抽离为2个自定义
Hooks
,并且相互传递响应式数据
-
加法功能-Hook
import { ref, watch } from 'vue';
const useAdd= ({ num1, num2 }) =>{
const addNum = ref(0)
watch([num1, num2], ([num1, num2]) => {
addFn(num1, num2)
})
const addFn = (num1, num2) => {
addNum.value = num1 + num2
}
return {
addNum,
addFn
}
}
export default useAdd
-
减法功能-Hook
//减法功能-Hook
import { ref, watch } from 'vue';
export function useSub ({ num1, num2 }){
const subNum = ref(0)
watch([num1, num2], ([num1, num2]) => {
subFn(num1, num2)
})
const subFn = (num1, num2) => {
subNum.value = num1 - num2
}
return {
subNum,
subFn
}
}
-
加减法计算组件应用
<template>
<div>
num1:<input v-model.number="num1" style="width:100px" />
<br />
num2:<input v-model.number="num2" style="width:100px" />
</div>
<span>加法等于:{{ addNum }}</span>
<br />
<span>减法等于:{{ subNum }}</span>
</template>
<script setup>
import { ref } from 'vue'
import useAdd from './useAdd.js' //引入自动hook
import { useSub } from './useSub.js' //引入自动hook
const num1 = ref(2)
const num2 = ref(1)
//加法功能-自定义Hook(将响应式变量或者方法形式暴露出来)
const { addNum, addFn } = useAdd({ num1, num2 })
addFn(num1.value, num2.value)
//减法功能-自定义Hook (将响应式变量或者方法形式暴露出来)
const { subNum, subFn } = useSub({ num1, num2 })
subFn(num1.value, num2.value)
</script>
在上面实例基础上添加个算平均的Hook
//平均功能-Hook
import { ref, watch } from "vue";
export function useAverage(addNum) {
const averageNum = ref(0);
watch(addNum, (addNum) => {
averageFn(addNum);
});
const averageFn = (addNum) => {
averageNum.value = addNum / 2;
};
return {
averageNum,
averageFn,
};
}
-
组件内应用
//组件内
//加法功能-自定义Hook(将响应式变量或者方法形式暴露出来)
const { addNum, addFn } = useAdd({ num1, num2 })
addFn(num1.value, num2.value)//主动调用,返回最新addNum
//平均功能-自定义Hook- hook传入参数值来其他hook暴露出来的变量
const { averageNum, averageFn} = useAverage(addNum)
averageFn(addNum.value)
Vue3自定义Hooks
可以灵活传递任何参数来改变它的逻辑,参数不限于其他hook
的暴露出来的变量,这提高了Vue3在抽象逻辑方面的灵活性
通过上述示例再来说说Vue3自定义Hooks和Vue2时代Mixin的关系:
Mixin不足
在 Vue 2 中,mixin 是将部分组件逻辑抽象成可重用块的主要工具。但是,他们有几个问题:
1、Mixin 很容易发生冲突:因为每个 mixin 的 property 都被合并到同一个组件中,所以为了避免 property 名冲突,你仍然需要了解其他每个特性。
2、可重用性是有限的:我们不能向 mixin 传递任何参数来改变它的逻辑,这降低了它们在抽象逻辑方面的灵活性。
hook优势
- Vue3自定义Hooks, 引用时将响应式变量或者方法显式暴露出来
- Vue3自定义Hooks可以灵活传递任何参数来改变它的逻辑,参数不限于其他hook的暴露出来的变量,这提高了Vue3在抽象逻辑方面的灵活性。
- 在Vue3自定义Hooks中,虽然加法和减法Hooks都返回了totalNum,但是利用ES6对象解构很轻松给变量重命名
总结:
Option Api
代码量少还好,代码量多容易导致高耦合!Vue2时代Option Api
,data
、methos
、watch
…..分开写,这种是碎片化的分散的,代码一多就容易高耦合,维护时来回切换代码是繁琐的!
Vue3时代Composition Api
,通过利用各种Hooks
和自定义Hooks
将碎片化的响应式变量和方法按功能分块写,实现高内聚低耦合
形象的讲法:Vue3自定义Hooks
是组件下的函数作用域的,而Vue2时代的Mixins
是组件下的全局作用域。全局作用域有时候是不可控的,就像var和let这些变量声明关键字一样,const和let是var的修正。Composition Api
正是对Vue2时代Option Api
高耦合和随处可见this
的黑盒的修正,Vue3自定义Hooks
是一种进步。
把Mixin和自定义Hook进行比较,一个是Option Api
的体现,一个是Composition Api
的体现。如果能理解高内聚低耦合的思想,那么就能理解为什么Vue3是使用Composition Api
,并通过各种自定义Hooks
使代码更强壮
原文始发于微信公众号(前端解码):Vue3必学技巧-自定义Hooks
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/49978.html