-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Vue推荐在构建大型应用时基于组件方式开发,使用组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B 。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的。这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性。
在 Vue.js 中,父子组件的关系可以总结为 props down, events up 。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。看看它们是怎么工作的。
父子组件,使用Props传递数据
组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。
prop 是父组件用来传递数据的一个自定义属性。子组件需要显式地用 props 选项 声明 “prop”:
Vue.component('child', {
// 声明 props
props: ['message'],
// 就像 data 一样,prop 可以用在模板内
// 同样也可以在 vm 实例中像 “this.message” 这样使用
template: '<span>{{ message }}</span>'
})
父组件中使用子组件并传值给子组件
<child message="hello!"></child>
单向数据流
prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解.
另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop 。如果你这么做了,Vue 会在控制台给出警告。
通常有两种改变 prop 的情况:
prop 作为初始值传入,子组件之后只是将它的初始值作为本地数据的初始值使用;
prop 作为需要被转变的原始值传入。
更确切的说这两种情况是:
定义一个本地数据,并且将 prop 的初始值设为本地数据的初始值。
定义一个基于 prop 值的计算属性。
注意在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
非父子组件通信,Event Bus
有时候非父子关系的组件也需要通信。在简单的场景下,使用一个空的 Vue 实例作为中央事件总线:
var bus = new Vue()
// 触发组件 A 中的事件(发布消息)
bus.$emit('id-selected', 1)
// 在组件 B 创建的钩子中监听事件(订阅消息)
bus.$on('id-selected', function (id) {
// ...
})
在更多复杂的情况下,你应该考虑使用专门的 状态管理模式.
vue2.0自定义事件
父组件可以使用 props 给子组件传递数据,那么反过来呢?该自定义事件出场了!
使用 v-on 绑定自定义事件
每个 Vue 实例都实现了事件接口 Events interface,即:
使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
下面是一个例子:
<div id="counter-event-example">
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>
Vue.component('button-counter', {
template: '<button v-on:click="increment">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
},
methods: {
increment: function () {
this.counter += 1
this.$emit('increment')
}
},
})
new Vue({
el: '#counter-event-example',
data: {
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1
}
}
})
全局状态管理,Vuex
基于SPA的应用,使用全局state共享数据,达到组件与组件间的通讯。
什么是Vuex?
什么时候应该使用Vuex?
尽管 Vuex 帮助我们处理共享状态管理,但是也带来了更多的思考和样板文件。这是一个短期效益和长期效益的权衡。
如果你没有开发过大型的单页应用(SPA)就立刻上 Vuex,可能会觉得繁琐然后排斥,这是很正常的 —— 如果是个简单的应用,大多数情况下,不用 Vuex 还好,你要的可能就是个简单的 全局事件总线(global event bus)。不过,如果你构建的是一个中到大型单页应用,当你在考虑如何更好的在 Vue 组件外处理状态时,Vuex 自然就是你的下一步选择。Redux 的作者有一句话说的不错:
原文:Flux libraries are like glasses: you’ll know when you need them.
译文:Flux 库就像眼镜:当你需要它们的时候你会懂的
总结
- 父子组件通讯使用Props传递数据
- 非父子组件通讯有二个种方案
- 大型应用推荐使用Vuex来管理全局state
- 小型应用直接使用全局事件总线来实现通讯,没有必要使用Vuex写过多的样板代码和更多思考代码应该如何写
Activity
HyperSimon commentedon Dec 23, 2016
有没有飞父子组件通讯的🌰可以参考下?
poezhang commentedon Mar 20, 2017
【vue2.0自定义事件】这一小节里面说的内容并不是,平行组件(非父子组件通信)间的通信,这一节写的仍然是父子间的通信吧。父与子A,父与子B间的通信,但是没有实现子A与子B间的通信
webplus commentedon Mar 20, 2017
简单的理解为父子组件间的通讯使用Props传递数据,非父子间组件通信使用Event Bus也就是事件的机制。
webplus commentedon Apr 7, 2017
子组件向父组件传值,第一张图应该较清楚了吧,就是Event的方式
huatten commentedon May 18, 2017
这不是官网文档吗?
zqinmiao commentedon Aug 17, 2017
你好,如上图的这句话。也就是说,如果我的prop是一个object的话,那么我在子组件中使用this.object.xxx='xxx';的话,那么在父组件中也就可以获取到改变后的object里的xxx属性的值了。
请问,这种方式虽然是能达到预期的效果,那么是不是不推荐这样做呢?
webplus commentedon Aug 18, 2017
是的
MontageD commentedon Mar 10, 2018
总结得挺清楚的。。
MontageD commentedon Mar 10, 2018
特别是子组件向父组件传递自定义事件那块