Vue从入门到精通入门篇之组件间通信
2019年1月14日
前言
最近事情比较多,已经一个月没有更新博客了,想想还是不能停下前进的脚步,今天抽空继续记录下本系列的内容,上篇文章说了组件开发,那么本篇就说说组件间通信的那些事吧!
通信模式
我们都知道,Vue
的数据模型为单向数据流+事件通知,其实组件间通信也是一样,大部分时候常用的也都是用 prop
事件向下传递数据,然后通过事件通知向上通知数据变化。或者使用 $refs
直接引用组件实例,调用组件方法,实现数据传递。除此之外,还可以使用 vuex
来统一管理数据及状态,然后通过调用 vuex
中的 Mutation
及 Action
来改变 state
中的数据。再或者使用 EventBus
来进行一个全局的事件通知改变数据。
prop + 事件通知
在 Vue
中,组件间通常通过 prop
来进行想下的数据传递,如:
<form-box
:value="val"
:data="form"
/>
既在子组件中定义 prop
属性,然后在父组件中将数据通过属性绑定的方式传递给子组件,这就实现了数据的自上像下传递,那么在子组件中就可以接受到来自父组件的数据,但是,如果某个数据我们想要从子组件传递给父组件要怎么处理了?通常使用事件通知的方式,既在父组件中绑定某个事件,当子组件内的某些数据发生变化的时候,可以通过 $emit
方法触发该事件,并将数据作为参数传递给父组件:
<!-- 父组件中 -->
<form-box
:value="val"
:data="form"
@submit="submitForm"
/>
<script>
export default {
motheds: {
submitForm(form) {
// do some thing
},
},
};
</script>
<!-- 子组件 -->
<script>
export default {
motheds: {
submit() {
// 触发submitForm事件,将data数据传递给父级
this.$emit('submitForm', this.data);
},
},
};
</script>
这就完成了一个简单的数据循环,该方式作为官方推荐的方式,我们很容易就看出改方式确实是简单实用,但是,它的缺点也很明显。在日常工作中,我们经常会遇到很多复杂的场景,还遇到很多类似组件嵌套结构比较深的场景,既一个父组件会包含很多层子孙级组件,那么在该中场景下,在使用该模式,很显然就有点麻烦,我们需要将数据一层层的通过 prop
向下传递,这相对还比较容易,但是当我们从最底层组件中,想要将数据传递给最上层组件时,就不得不在每层组件中都定义相似的方法,然后不断的向上触发事件,这显然有点不太合适,这就使得另一种方式的出现!
($refs
or $parent
or $root
) + 实例方法调用
除了上面说的使用 props
传递数据以外,我们也可以使用 $refs
or $parent
or $root
引用组件实例,然后通过实例,直接调用实例方法,并且将要传递的数据通过参数进行传递:
<!-- 父组件中 -->
<form-box
ref="formBox"
:value="val"
:data="form"
@submit="submitForm"
/>
<script>
export default {
motheds: {
submitForm(form) {
// do some thing
},
},
mounted() {
this.$refs.formBox.setValue('xxx');
},
};
</script>
<!-- 子组件 -->
<script>
export default {
motheds: {
setValue(val) {
this.value = val;
},
submit() {
// 调用父组件submitForm事件,将data数据传递给父级
this.$parent.submitForm('xxx');
},
},
};
</script>
通过上面的例子我们能很清楚的看出这种方式的使用方式,但是这里需要说明的是,这种方式会导致组件间的强耦合,并不推荐使用!
vuex方式
除了上面说的方法以外,在一些复杂场景中,我们更多的会使用 vuex
来统一进行数据管理,这有个好处就是它能很容易的处理夸层级的组件间的数据通信,既统一在 vuex
的 state
中定义数据,然后在 vuex
的 Mutation
中定义同步方法用来改变 state
中的数据,在 Action
中定义异步方法,通过触发 Mutation
或者直接改变 state
数据,从而达到全局数据通信的目的!
common vuex:
// common vuex
const state = {
form: {
age: '',
name: '',
address: ''
},
};
const mutations = {
setFormData({ state }, data) {
this.state = JSON.parse(JSON.stringify(data || {}));
}
};
const actions = {
getFormData({ commit }) {
ajax.get('http://xxx.com/xxx', (res) => {
if (res.code === 200) {
commit('setFormData', res.data);
}
})
}
}
最外层组件:
<script>
import { mapState } from 'vuex';
export default {
computed: {
...mapState({
form: state => state.common.form,
}),
}
}
</script>
内层组件:
<script>
export default {
data() {
return {
form: {
name: '',
age: '',
address: '',
},
};
},
methods: {
submit() {
this.$store.commit('setFormData', { ...this.form });
}
}
}
</script>
如上面 vuex
的代码,我们定义了 state
中的数据 form
,当在form表单组件中,我们改变了数据之后,通过调用 Mutation
里的 setFormData
方法重新设置 state
中的数据 form
,这样只需要在外层组件中绑定 state
中的数据 form
,就可以实时拿到最新的 form
数据了,这样也就实现了夸组件间的数据通信!
EventBus方式
除了上面说的两种方式以外,还有一种情况我们会经常遇到,比如最内层组件并不依赖外层组件的数据,但是当最内层数据变化时,又需要通知到最外层组件,这个时候我们就可以使用 EventBus
方式。
其实作为一个前端,对于自定义事件的订阅/发布模式肯定是不陌生的,EventBus
说白了,就是一个全局的事件订阅/发布管理器,我们通过全局订阅事件,并且在合适的时候触发事件,即可实现跨组件数据通信,关于 EventBus
的具体实现,可以参考我以前写的一个项目里的事件订阅/发布模块:事件订阅发布;这里就不在重复实现相关模块了!
具体使用中,我们只需要实现一个事件订阅/发布管理模块,并且进行一下简单的封装,将其封装成 vue
插件,然后再使用 Vue.use
方法注册一下即可,具体 vue
插件的封装,就不在本篇来讲了,以后会有一篇文章来专门说明 vue
插件开发,现在我们就当该插件已经实现,我们来看一下使用方法;
首先在main.js里面进行全局注册:
import Vue from 'vue';
import EventBus from '@/utils/event-bus';
Vue.use(EventBus);
在外层组件内进行事件订阅:
<script>
export default {
mounted() {
this.$bus.$on('submit-form', (data) => {
// do some thing
});
},
};
</script>
在内层组件中触发事件:
<script>
export default {
data() {
return {
form: {
name: '',
age: '',
address: '',
},
};
},
methods: {
submit() {
this.$bus.$emit('submit-form', { ...this.form });
},
},
};
</script>
这样我们就通过全局事件订阅/发布模式实现了跨组件间的通信。
结尾
到这里,我们已经介绍了常用的4种组件间通信的方式,这几种方式各有利弊,我们可以根据具体的业务场景来选择使用哪种方式比较合理!
转载说明
本文允许全文转载,转载请注明来源: 平凡公子 - vue从入门到精通入门篇之组件间通信