前言
provide/inject、mixins是我们开发过程中经常会使用到的API,这几个API的相关了解大家知道多少呢?且听我们缓缓道来
一、provide/inject
provide
和 inject
通常成对一起使用,使一个祖先组件作为其后代组件的依赖注入方,无论这个组件的层级有多深都可以注入成功,只要他们处于同一条组件链上。
1.1 provide(提供)/ inject(注入)介绍
provide
:用于提供可以被后代组件注入的值。inject
:用于声明要通过从上层提供方匹配并注入当前组件的属性
1.2 provide(提供)/ inject(注入)使用
1.2.1 provide(提供)
provide
选项应当是一个对象或是返回一个对象的函数。这个对象包含了可注入其后代组件的属性,你可以在这个对象中使用 Symbol 类型的值作为 key
1.2.2 inject(注入)
-inject
选项应该是以下两种之一:
-
一个字符串数组
vueexport default { inject: ['foo'], created() { console.log(this.foo) } }
-
一个对象,其 key 名就是在当前组件中的本地绑定名称,而它的值是以下两种之一:
- 匹配可用注入的key(string 或 Symbol)
- 一个对象
- 它的 from 属性是一个key(String 或 Symbol),用于匹配可用的注入
- 它的 default 属性用作候补值,和props 的默认值类似,如果它是一个对象,那么应该使用一个工厂函数来创建,以避免多个组件共享同一个对象
注入属性的值 = 匹配的属性 ? 匹配的属性值 : (默认值 || undefind)
1.2.3 Vue2 的 provide(提供)/ inject(注入)使用
provide / inject 类似于消息的订阅和发布。provide 提供或发送数据, inject 接收数据。
vue
//父组件
export default{
provide:{
info:"提供数据",
}
}
//子组件
export default{
inject:['info'],
mounted(){
console.log("接收数据:", this.info) // 接收数据:提供数据
}
}
1.2.4 Vue3 的 provide(提供)/ inject(注入)使用
在组合式API中使用 provide/inject ,两个只能在 setup 期间调用,使用之前,必须从 Vue 显示导入 provide/inject 方法
参数:
- provide 函数接收两个参数:
provide( name,value )
- name: 定义提供 property 的 name
- value: property 的值
- inject 函数有两个参数:
inject(name,default)
- name: 接收 provide 提供的属性名
- default:设置默认值,可以不写,是可选参数
vue
//父组件代码
<script>
import { provide } from "vue"
export default {
setup(){
provide('info',"值")
}
}
</script>
//子组件 代码
<template>
{{info}}
</template>
<script>
import { inject } from "vue"
export default {
setup(){
const info = inject('info')
return{
info
}
}
}
</script>
1.3 provide 和 inject 的优缺点
- 优点:
- 解决多嵌套组件时,运用prop层层传递的问题
- 缺点:
- 无法追踪数据的来源:在任意层级都能访问导致数据追踪比较困难,不知道是哪一层声明了这个,不知道哪一个层级或若干个层级使用了
- 导致组件间的耦合:它将导致于组件间的耦合,使得组件复用性收到影响
1.4 其它
1. provide 和 inject 出现的背景
多层级的嵌套的组件,形成了一颗巨大的组件树,而某个深层的子组件需要一个较远的祖先组件中的部分数据。在这种情况下,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦:
注意,虽然这里的 <Footer>
组件可能根本不关心这些 props,但为了使 <DeepChild>
能访问到它们,仍然需要定义并向下传递。如果组件链路非常长,可能会影响到更多这条路上的组件。这一问题被称为"prop 逐级透传",显然是我们希望尽量避免的情况。
provide
和 inject
可以帮助我们解决这一问题。 一个父组件相对于其所有的后代组件,会作为依赖提供者 。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。
2. provide 和 inject 为什么不是响应式
- 官方解释:当提供 / 注入响应式的数据时,建议尽可能将任何对响应式状态的变更都保持在供给方组件中。这样可以确保所提供状态的声明和变更操作都内聚在同一个组件内,使其更容易维护。
- 个人理解:会增加组件的复杂度,使得组件维护成本增加
二、mixins
2.1 mixins介绍
一个包含组件选项对象的数组,这些选项都将被混入到当前组件的实例中。
mixins
选项接受一个 mixin 对象数组,这些 mixin 对象可以像普通的实例对象一样包含实例选项,它们将使用一定的选项合并逻辑与最终的选项进行合并。
举例来说,如果你的 mixin 包含一个created
钩子,而组件自身也有一个,那么这两个函数都会被调用
-
mixins本质:其实就是一个JS对象,它可以包含我们组件中任意功能选项,如
data
、components
、methods
、created
、computed
等等 -
mixins作用:将相同的逻辑和功能抽离出来,分成单个文件,组件只需引入 mixins 就可以实现相同功能
在Vue2中,mixins 是创建可重复组件逻辑的主要方式。尽管在Vue3中保留了 mixins 支持,但对于组件间的逻辑复用,使用组合式 API 的组合式函数是现在更推荐的方式。
2.2 mixins使用
2.2.1 局部混入
使用大致步骤如下流程:
-
在src文件夹中创建mixins文件夹,在里面去写对应的mixin.js文件。如下所示:
jsvar myMixin = { created: function () { this.hello() }, methods: { hello: function () { console.log('hello from mixin!') } } }
-
在组件中引入mixin,去使用如下所示:
jsVue.component('componentA',{ mixins: [myMixin] })
该组件在使用的时候,混合了mixin
里面的方法,在自动执行created
生命钩子,执行hello
方法
2.2.2 全局混入
通过Vue.mixin()
进行全局的混入,如下所示:
js
Vue.mixin({
created: function () {
console.log("全局混入")
}
})
使用全局混入需要特别注意,因为它会影响到每一个组件(包括第三方组件)
- 使用场景:插件的编写
2.3 mixins特性
-
mixins中的生命周期会与引入mixins的组件的生命周期整合在一起调用,而且mixins中的生命周期函数会比引入mixins的组件调用的快
如果相同选项为生命周期钩子的时候,会合并成一个数组,先执行mixin的钩子,再执行组件的钩子
-
组件的
data
、methods
、filters
会覆盖mixins里的同名data
、methods
、filters
-
不同mixin里的同名方法,会按照引进的顺序,最后的覆盖前面的同名方法
2.4 mixins的优缺点
- 优点:
- 提高代码复用性
- 无需传递状态
- 维护方便,只需要修改一个地方即可
- 缺点:
-
变量来源不明确(隐式引入),不利于阅读,使得代码变得难以维护
- 组件中引入mixin,并且直接隐式调用 mixin 里的变量/方法,这会让我们有时候找不到这个变量/方法的出处
- 同一个组件可以引入多个mixin,并且直接调用mixin里的变量/方法,这会让我们有时候混乱 区分不出这些变量和方法 分别是哪个mixin里的?
-
多个mixins的生命周期会融合到一起运行,但是同名属性、方法无法融合,可能会导致冲突或覆盖
比如组件1中的方法要输入属性info,但是组件2中也有同名属性info,且覆盖了组件1中的属性info,那么当执行组件1中的方法时,输出的确实组件2中的书写。这个我们可以避免,但是一不小心就会导致冲突,很容易制造混乱
-
mixins和组件可能出现多对多的关系,复杂度较高
即一个组件可以引用多个mixins,一个mixins也可以被多个组件引用
-
2.5 其它
1. mixins 与 vuex的区别
vuex:用来做状态管理的,里面定义的变量在每个组件中均可以使用和修改,在任意组件中修改次变量的值后,其他组件中此变量的值也会随之修改
Mixins:可以定义共用的变量,在每个组件中使用,引入组件中之后,各个变量是相互独立的,值在修改在组件中不会相互影响
2. mixins 与 公共组件的区别
组件:在父组件中引入组件,相当于在父组件中给出一个独立的空间供子组件使用,然后根据props进行父到子组件的传值,但本质上两者是相对独立的
Mixins:则是在引入组件之后与组件中的对象和方法进行合并,相当于扩展了父组件的对象与方法,可以理解为形成一个新的组件
三、extends
3.1 extends介绍
extends 要继承的"基类"组件。就是一个组件可以继承另一个组件的组件选项
!!!不建议用于组合式 API
extends
是为选项式 API 设计的,不会处理setup()
钩子的合并。在组合式 API 中,逻辑复用的首选模式是"组合"而不是"继承"。如果一个组件中的逻辑需要复用,考虑将相关逻辑提取到组合式函数中。
如果你仍然想要通过组合式 API 来"继承"一个组件,可以在继承组件的
setup()
中调用基类组件的setup()
:
jsimport Base from './Base.js' export default { extends: Base, setup(props, ctx) { return { ...Base.setup(props, ctx), // 本地绑定 } } }
3.2 extends使用
js
const CompA = { ... }
const CompB = {
extends: CompA,
...
}
3.3 其它
1. extends 与 mixins 的区别
从显示角度来看,extends 几乎和 mixins 相同。通过 extends 指定的组件将会当做第一个mixin来处理。
然而,extends 和 mixins 表达的是不同的目标。mixins 选项基本用于组合功能,extends 则一般更关注继承关系