前言
Vue
中的 Hooks
也算是三年前的东西了,想当时在 React
中写 Hooks
函数算是比较流行的写法。Vue
中一直是 options
配置化写法,所有的钩子和数据都在一个对象中给你提供了,你只需要将你的数据和处理逻辑放到对应的框里面去。这也是Vue一直以来流行的原因之一了。简单。现在 Vue
也支持 Hooks
写法了,而且在工作中也用的比较多。
Mixins的痛点
Vue2
中如果要在组件层面进行功能模块的封装大多使用的是 Mixins 进行功能模块的封装。Mixins:混入。主要功能是将公共的函数方法加入到需要的组件中,可以将每个组件的生命周期或者是公共方法进行封装,组件在各自的生命周期内执行时。首先会执行 Mixins 中指定钩子的方法,然后执行组件中的方法。
// 创建 Mixin 对象
const myMixin = {
data() {
return {
message: 'Hello, Mixins!'
}
},
methods: {
sayHello() {
console.log(this.message);
}
}
}
// 应用 Mixin 到组件
const myComponent = Vue.extend({
mixins: [myMixin],
created() {
this.sayHello(); // 输出 "Hello, Mixins!"
}
})
如上所示。使用 Mixins 有一些优点,例如:
- 提高代码复用性和可维护性。
- 在多个组件之间共享和重用代码。
Mixins 的缺点最让我无法忍受:
- 方法与属性难以追溯。
export default {
mixins: [ a, b, c, d, e, f, g ], // 这表示它混入了很多能力
mounted() {
console.log(this.name)
// 懵逼??!这个 this.name 来自于谁?
}
}
- 命名冲突和重复代码。
当我想要复用两个使用
mixin
写的两个功能( a-name.js, b-name.js ),当然,正常看来直接引入就可以使用了,但是当这两个mixin
写法的功能 心意相通 的时候定义了几个相同的变量时,我们心里就开始崩溃了(:tw-1f631:)。这时我就非常想要怀疑mixin
是一种合理的共享复用功能的方法吗?
为什么使用 Hooks
“高度聚合,可阅读性提升”。伴随而来的便是 “效率提升,bug变少”。
对于 Vue 中的hooks ,有以下的定义:
在 vue 组合式API里,以 “use” 作为开头的,一系列提供了组件复用、状态管理等开发能力的方法。
hooks 在 Vue 中完全解决了mixin 写法的痛点。代码没有痛点,处处都是晴天 。Vue3 中的 hooks 相比于 Vue2 中的 mixin:
- 方法和属性好追溯吗?这可太好了,谁产生的,哪儿来的一目了然。
- 会有重名、覆盖问题吗?完全没有!内部的变量在闭包内,返回的变量支持 as 别名。
- 多次使用?我直接梅开N度。
// 单个引入 变量 的写法
const { myName, getAge } = useUser();
// 梅开二度的写法
const { myName as firstName, get as firstGetAge } = useUser();
const { myName as secondName, get as secondGetAge } = useUser();
Hooks 基础用法示例
这是一个最简单的 useFoo hooks 实现的🌰。
// src/hooks/useFoo.ts
export function useFoo() {
let message = '我是 useFoo 中的 message';
function test() {
console.log('useFoo 的 test');
}
return {
message,
test
};
}
// App.vue
<script setup>
import { useFoo } from "./hooks/useFoo";
const { message: fooMessage, test } = useFoo();
</script>
<template>{{ fooMessage }}<button @click="test">按钮</button></template>
Hooks 搭配长步骤页面使用的示例
需求:
实现一个长步骤页面(一个步骤都是一个页面组件,每一步都有相对独立的逻辑处理,不同的场景下有不同的步骤组合)。
最初的实现:
将全部逻辑写到一个组件中,每一个步骤都通过 el-steps key 来控制,通过 v-if 来控制不同步骤下不同组件的现实。当然这样做也能实现,但是也需要将每一步骤的逻辑理清楚,不然写着写着一头雾水,真实手在前面写,脑子在后面追。而且当我写完了一个场景后,又提出一个新场景,然而步骤之间的组合却不相同,所以这种将所有步骤写在一个组件中的方法是行不通了。
使用hooks写法将逻辑分离
将每一个步骤拆分成一个步骤,一个步骤写成一个hooks,在不同的场景下,可以将其按照需求复用。
定义如下 hooks 函数
按照设计定义类似如下不同步骤,每个步骤拥有标识 key,每个步骤有上图所示独立的处理逻辑 hooks
// 上传
const steps1 = [
{
title: '上传文件',
key: 'upload-data-set',
},
{
title: '预览数据',
key: 'data-set-design',
},
{
title: '数据集设置',
key: 'create-data-set',
},
];
// 替换
const steps2 = [
{
title: '上传文件',
key: 'upload-data-set',
},
{
title: '预览数据',
key: 'data-set-design',
},
{
title: '字段匹配',
key: 'data-field-replace',
},
];
接下来,只需要在每个步骤hooks中,对应的逻辑即可,以 useFieldUpload 为🌰:
// useFieldUpload.ts
import { computed, h, ref, watch } from 'vue';
import { useFieldPage } from './useFilePage';
// ...
export const useFileUpload = () => {
// ... 逻辑
return {
// ...
};
};
在 hooks 中使用 useRouter useRoute
useRouter 和useRoute 只能在 vue 的setup 函数中使用,如果需要在 hooks 中使用,直接引入相应的 hooks 会出现 undefined。 所以我们可以在写hooks 中,可以在定义时传入相应的配置值。 举个例子: