文章目录
- 组件间通信的概念
- 组件间通信的分类
- 组件间通信的方案
- 父组件将方法传递给子组件(props)
- 子组件向父组件传值(emit)
- 通过 ref 属性获取DOM元素
- EventBus
- p a r e n t 或 parent 或 parent或 root
- a t t r s 与 attrs 与 attrs与 listeners
- provide 与 inject
- `vuex`实现组件通信
组件间通信的概念
开始之前,我们把组件间通信这个词进行拆分
- 组件
- 通信
都知道组件是vue
最强大的功能之一,vue
中每一个.vue
我们都可以视之为一个组件通信指的是发送者通过某种媒体以某种格式来传递信息到收信者以达到某个目的。广义上,任何信息的交通都是通信组件间通信即指组件(.vue
)通过某种方式来传递信息以达到某个目的举个栗子我们在使用UI
框架中的table
组件,可能会往table
组件中传入某些数据,这个本质就形成了组件之间的通信
组件间通信的分类
- 父子组件之间的通信
- 兄弟组件之间的通信
- 祖孙与后代组件之间的通信
- 非关系组件间之间的通信
组件间通信的方案
vue
中8种常规的通信方案
- 通过 props 传递
- 通过 $emit 触发自定义事件
- 使用 ref
- EventBus
- p a r e n t 或 parent 或 parent或root
- attrs 与 listeners
- Provide 与 Inject
- Vuex
父组件将方法传递给子组件(props)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><script src="vue2.5.16.js"></script>
</head><body><div id="app"><!-- 父组件向子组件 传递 方法,是通过 事件绑定机制; v-on。当我们自定义了 一个 事件属性 parent-show(这个地方不能用驼峰命名)之后,--><!-- 那么,子组件就能够,通过 emit 来调用 传递进去的 这个 方法了 --><!-- 【第一步】。意思是说,`show`是父组件的方法名,`parent-show`是自定义的时间属性,稍后要在子组件中用到 --><component1 @parent-show='show'></component1></div><!-- 定义子组件的模板 --><template id="myTemplate"><!-- 【第二步】按照正常的写法来:点击按钮,调用子组件的方法 --><div @click="childClick">我是子组件,点击调用父组件的方法</div></template><script>// 创建 Vue 实例,得到 ViewModelvar vm = new Vue({el: '#app',data: { //父组件的data// msg: '父组件中的数据'},methods: {show: function () { // 定义父组件的show方法console.log('父组件提供的方法');}},components: {component1: { //将子组件的名称定义为 component1template: '#myTemplate',data() { // 子组件的datareturn {// content: '子组件私有的数据 content'}},props: [''],directives: {},filters: {},components: {},methods: {childClick() {// 当点击子组件的按钮时,如何 拿到 父组件传递过来的 func 方法,并调用这个方法???// emit 英文原意: 是触发,调用、发射。意思是,触发父组件的方法// 【第三步】 在子组件的方法中,通过 emit 触发父组件的方法this.$emit('parent-show');}}}}});</script>
</body></html>
效果如下:(点击子组件,触发了父组件的方法)
子组件向父组件传值(emit)
如果要实现子组件向父组件传值,代码是类似的,我们只需要在子组件通过emit
触发父组件的方法时,把子组件的参数带出去就可以了
- 适用场景:子组件传递数据给父组件
- 子组件通过
$emit触发
自定义事件,$emit
第二个参数为传递的数值 - 父组件绑定监听器获取到子组件传递过来的参数
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><script src="vue2.5.16.js"></script>
</head><body><div id="app"><component1 @parent-show='show'></component1></div><!-- 定义子组件的模板 --><template id="myTemplate"><h2 @click="childClick">我是子组件,点击调用父组件的方法</h2></template><script>// 创建 Vue 实例,得到 ViewModelvar vm = new Vue({el: '#app',data: { //父组件的data// msg: '父组件中的数据'},methods: { // 定义父组件的方法show: function (arg1, arg2) { //【第二步】父组件里放两个参数,这个两个参数就代表着子组件中的`child 123`、`child 789`console.log('父组件提供的方法');console.log('打印子组件传递过来的参数。参数一:' + arg1 + ',参数二:'+ arg2);}},components: {component1: { //将子组件的名称定义为 component1template: '#myTemplate',data() { // 子组件的datareturn {// content: '子组件私有的数据 content'}},props: [''],directives: {},filters: {},components: {},methods: {childClick() {// 子组件如果要给父组件传递参数,在触发 emit 的时候,通过参数的形式带出去就可以了// 【第一步】在子组件里,我们带两个参数出去,传给父组件this.$emit('parent-show', 'child 123', 'child 789');}}}}});</script>
</body></html>
运行结果:(点击<h2>
之后)
Chilfen.vue
this.$emit('add', good)
Father.vue
<Children @add="cartAdd($event)" />
通过 ref 属性获取DOM元素
- 父组件在使用子组件的时候设置
ref
- 父组件通过设置子组件
ref
来获取数据
父组件
<Children ref="foo" /> this.$refs.foo // 获取子组件实例,通过子组件实例我们就能拿到对应的数据
EventBus
- 使用场景:兄弟组件传值
- 创建一个中央事件总线
EventBus
- 兄弟组件通过
$emit
触发自定义事件,$emit
第二个参数为传递的数值 - 另一个兄弟组件通过
$on
监听自定义事件
Bus.js
// 创建一个中央时间总线类
class Bus { constructor() { this.callbacks = {}; // 存放事件的名字 } $on(name, fn) { this.callbacks[name] = this.callbacks[name] || []; this.callbacks[name].push(fn); } $emit(name, args) { if (this.callbacks[name]) { this.callbacks[name].forEach((cb) => cb(args)); } }
} // main.js
Vue.prototype.$bus = new Bus() // 将$bus挂载到vue实例的原型上
// 另一种方式
Vue.prototype.$bus = new Vue() // Vue已经实现了Bus的功能
Children1.vue
this.$bus.$emit('foo')
Children2.vue
this.$bus.$on('foo', this.handle)
p a r e n t 或 parent 或 parent或 root
- 通过共同祖辈
$parent
或者$root
搭建通信桥连
兄弟组件
this.$parent.on('add',this.add)
另一个兄弟组件
this.$parent.emit('add')
a t t r s 与 attrs 与 attrs与 listeners
- 适用场景:祖先传递数据给子孙
- 设置批量向下传属性
$attrs
和$listeners
- 包含了父级作用域中不作为
prop
被识别 (且获取) 的特性绑定 ( class 和 style 除外)。 - 可以通过
v-bind="$attrs"
传⼊内部组件
// child:并未在props中声明foo
<p>{{$attrs.foo}}</p> // parent
<HelloWorld foo="foo"/>
// 给Grandson隔代传值,communication/index.vue
<Child2 msg="lalala" @some-event="onSomeEvent"></Child2> // Child2做展开
<Grandson v-bind="$attrs" v-on="$listeners"></Grandson> // Grandson使⽤
<div @click="$emit('some-event', 'msg from grandson')">
{{msg}}
</div>
provide 与 inject
在祖先组件定义provide
属性,返回传递的值
- 在后代组件通过
inject
接收组件传递过来的值
祖先组件
provide(){ return { foo:'foo' }
}
后代组件
inject:['foo'] // 获取到祖先组件传递过来的值
vuex
实现组件通信
-
适用场景: 复杂关系的组件数据传递
-
Vuex
作用相当于一个用来存储共享变量的容器
-
state
用来存放共享变量的地方 -
getter
,可以增加一个getter
派生状态,(相当于store
中的计算属性),用来获得共享变量的值 -
mutations
用来存放修改state
的方法。 -
actions
也是用来存放修改state的方法,不过action
是在mutations
的基础上进行。常用来做一些异步操作