「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战」。
30. 举一个$attrs
和 $listeners
的应用场景
比如,有 A、B、C 三个组件,调用关系如下: A -> B -> C
B 调用 C 时,在 C 上写$attrs
和$listeners
,就可以把 C 的属性和事件绑定在 B身上,A 调用 B 时,就可以拿到 C 上的属性和事件。
这种写法在对一些组件进行二次封装时非常有用,比如,对 element-ui 的级联选择器组件 el-cascader
进行二次封装,只改了很小的一个功能,其他功能保持原样。
就可以定义一个 custom-cascader
组件
custom-cascader 内部
...
<el-cascader
v-bind="$attrs"
v-on="$listeners"
...
/>
...
调用 custom-cascader 的地方
<custom-cascader
:options="xxx"
size="mini"
@remove-tag="xxx"
/>
这些 el-cascader 的属性和事件都可以直接使用,不用再通过 props 传递一层了,非常方便。
31. 用过 provide 和 inject 吗?
provide 和 inject 一般用于层级很深的组件之间通信。
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。 -- vue文档
日常的业务组件一般不会用,因为容易造成混淆,而且一般的项目都用了 Vuex
。
provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。 -- vue文档
正如文档所说, provide 和 inject 用来开发组件库很有用,因为一般开发组件库不会引类似于 Vuex 这样的三方依赖,就只有用 Vue 本身提供的 provide 和 inject 了。
比如, element-ui 的源码中就大量地使用到了 provide 和 inject。
而且他的用法是直接把这个组件实例 provide 过去,像这样
需要用到的地方,直接调这个实例上的属性和方法
provide 和 inject 基本使用
当然,vue 文档虽然不推荐我们在业务开发中用,但有时候用一用还是无伤大雅的,provide 和 inject 基本使用如下:
// A.vue
export default {
provide: {
name: 'lin'
}
}
// B.vue
export default {
inject: ['name'],
mounted () {
console.log(this.name); // lin
}
}
可以看到,在 A.vue 里,我们设置了一个 provide: name,值为 lin,它的作用就是将 name 这个变量提供给它的所有子组件。
而在 B.vue 中,通过 inject
注入了从 A 组件中提供的 name 变量,那么在组件 B 中,就可以直接通过 this.name 访问这个变量了,它的值也是 lin。
32. provide 和 inject 是响应式的吗?
provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。 -- vue 文档
写个 demo 试一试:
// 父组件内:
<Child />
<button @click="changeName">change</button>
data() {
return {
name: 'lin',
person: {
name: 'Allen'
}
}
},
provide() {
return {
name: this.name,
person: this.person
}
},
methods: {
changeName() {
this.name = 'lin12345'
this.person.name = 'Adel'
}
}
// 子组件内:
<p>{{ name }}</p>
<p>{{ person }}</p>
inject: ['name', 'person']
果然如此,一般的变量不可响应,传入对象,对象的属性可以响应。
33.Vue 组件之间的通信方式有哪些?
常用的:
-
父子组件交互,
props
和$emit
,vue单向数据流。 -
使用
$attrs
和$listeners
,集成子组件的属性和事件,在对一些组件进行二次封装时非常有用,可以不用写具体的属性或事件名,直接获取。 -
使用
Vuex
进行状态管理
不常用的:
-
使用
$refs
获取组件实例,进而获取数据 -
组件中可以使用
$parent
和$children
获取到父组件实例和子组件实例,进而获取数据 -
使用
eventBus
进行跨组件触发事件,进而传递数据,一般用得比较少 -
使用
provide
和inject
,一般用于基础组件开发,或用于跨很多层的组件传值。 -
通过
mixins
传公共逻辑。
其实,像provide/inject
还有 mixins
这种通信方式,写组件库没啥,但最好不要用在业务组件里。
因为项目复杂了之后,很容易造成迷惑,不知道数据是从哪里传递过来的,全局搜调用的属性名或者函数名,结果出来很多个,太令人难受了。
如果是通过文件夹的形式管理业务组件,每个文件夹有自己内部的mixins,这种方式还是可以接受的。
但其实也很难受,日常代码开发由上下横跳变成左右横跳,不过这样可以让我们的单个文件代码少一点,还是要优雅一点。
像 $refs
、$parent
、$children
,我一般也用得少,除非迫不得已一定要用,因为这些组件通信方式用了之后,数据的流向不是一目了然的,在这个文件里搜属性或者方法,搜不到来源,要把这个文件的代码仔细读一下才能清楚数据流向,开发效率就降低了。
如果觉得文章对你有帮助,就给我一个小小的赞吧^ _ ^
往期
Vue 100问(27-29)说一下你对 vue 插槽的理解
Vue 100问(18-22问)谈谈你对 Vue 生命周期的理解
Vue100问(第5问)为什么 v-for 的 key 值不能是 index?