前端 Vue 框架中,当涉及到代码复用时,最为常见且广泛使用的工具有三个,它们分别是 Component(组件)、Hooks(钩子)和 Mixins(混入)。本文将重点探讨 Mixins 和 Hooks 之间的差异,旨在更好地理解和应用 Hooks 生态系统。
Mixins
我们在开发过程中,常常会遇到重复的代码逻辑片段,mixins(混入)
就是将这部分相同的逻辑片段,单独抽离出来,进行封装。通过将 mixins 引入需要使用该段逻辑的页面,从而实现一段代码,多页面复用的效果。
mixins 的特点:
顾名思义,mixins(混入),即将当前的代码片段混入到的父组件中
- mixins 与父组件共用生命周期函数,mixins 中定义的生命周期部分,将自动整合进父组件的生命周期中
- 若 mixins 中定义的变量与父组件重名,将优先采用父组件中定义的变量
- 若 mixins 与其他引入父组件中的 mixins 组件中定义的变量重名,将按照 mixins 的引入顺序,采用后引入者中定义的变量
mixins 的使用
1. 在 Vue2 中使用
//mixins 文件 export const testMixins = { data(){ return { list:[1,2,3,4,5], msg:"我是 mixins 中的数据" } }, computed:{ }, methods:{ total(){ let sum = list.reduce((pre,cur)=>{ return pre+cur },0) return sum }, getList(){ return this.list } }, }
在父组件中引入 mixins:
<!-- 父组件引入 mixins --> <template> <div> <div>我是父组件</div> <div>{{msg}}</div> </div> </template> <script> import testMixins from './testMixins' export default { mixins:[testMixins], data() { return { name:'father', count:0 } }, mounted() { console.log('我是父组件中的 mounted()') this.count = total() }, } </script> <style lang="'scss" scoped> </style>
由于在 vue3 中强烈推荐使用 hooks 替代 mixins 使用,因此此处不再赘述 mixins 的 vue3 写法。
mixins 的缺点:
通过上述的使用示例,我们不难发现 mixins 在使用中存在以下致命缺陷
- 由于 mixins 混入的特性,其中定义的变量相当于隐式引入了父组件,从而导致变量难以定位到其定义的具体位置
- 若父组件仅需要 mixins 中某一小段逻辑,通过 mixins 的方式还是只能将整个 mixins 文件引入后进行使用,无形中增加了无效代码的引用
- 最致命的便是多 mixins 引入重名的情况
例如:当前页面引入了多个 mixins,每个 mixins 内均定义了一个变量名为 list,我既想使用 mixinsA 中的 list 又想使用 mixinsB 中的 list 就成为了一个令人头疼的问题。
Hooks
很显然,越来越多的框架开发者们也注意到了 mixins 的上述缺陷,因此急需一种新的代码复用逻辑的优化方案,由此基于 hooks 实现代码复用的方式横空出世。
所谓hooks
直译过来便是钩子函数。我们可以将mixins
理解为一个将<script></script>
标签部分的 js 逻辑代码片段文件,而 hooks 正如其中文译名,不同于mixins
其本质上是一个可以复用的函数,其在 vue3 的 setup()中调用。
mixins 的使用
1. 在 Vue3 中的基础用法
在项目路径下新建一个名为 hooks 的文件夹,在里面新建名为 test.js 的一个 hooks 文件。
注意 hooks 组件的命名规范为,use+hooks 功能名
的大驼峰命名方式,例如:需要封装一个 table 复用的 hooks,则命名为useTable.js
//useTest.js import { ref } from "vue"; export default function useTest() { //定义变量 const list = ref([1, 2, 3, 4, 5]); const msg = ref("我是 hooks 中的数据"); //使用生命周期函数 onMounted(() => { console.log("我是 hooks 中定义的 onMounted()"); }); //定义方法 const total = () => { let sum = list.reduce((pre, cur) => { return pre + cur; }, 0); return sum; }; const getList = () => { return list.value }; //将需要使用的数据和函数暴露出去 return { list, msg, total, getList }; }
在父组件中引入 hooks:
<!--父组件中引入 hooks --> <template> <div> <div>我是父组件的数据</div> <!-- 使用 hooks 中的变量 --> <div>{{msg}}</div> <!-- 使用 hooks 中的方法进行求值 --> <div>{{count}}</div> </div> </template> <script lang="ts" setup> import useTest from './hooks/useTest.js' //需按需求自由 hooks 中的变量和方法 const {msg,total,list} = useTest() const count = ref(total) </script> <style lang="scss" scoped> </style>
hooks 的优势和不足
优势:
hooks
让开发者可以根据当前页面的需求,选择性的引入 hooks 中的变量和方法,减小无效代码的复用- 不同于
mixins
,hooks
中引入的变量通过hooks 名.变量名
的方式进行使用,从而避免了变量重名的问题,即使变量重名,只要对应的hooks
组件不重名,就可以通过hooks 名.变量名
的方式进区分。
不足:
- 由于
hooks
本身是一个函数,因此调用 hooks 中定义的方法会产生闭包,大量滥用hooks
,不可避免的存在一定的内存泄露问题,不过大部分情况下 hook 的表现还是非常优秀的。