New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue 2.0开发实践(组件间通讯) #10

Open
webplus opened this Issue Oct 21, 2016 · 9 comments

Comments

Projects
None yet
6 participants
@webplus
Owner

webplus commented Oct 21, 2016

Vue推荐在构建大型应用时基于组件方式开发,使用组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B 。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的。这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性。

在 Vue.js 中,父子组件的关系可以总结为 props down, events up 。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。看看它们是怎么工作的。

props down, events up

父子组件,使用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共享数据,达到组件与组件间的通讯。

global state

什么是Vuex?

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写过多的样板代码和更多思考代码应该如何写
@HyperSimon

This comment has been minimized.

HyperSimon commented Dec 23, 2016

有没有飞父子组件通讯的🌰可以参考下?

@poezhang

This comment has been minimized.

poezhang commented Mar 20, 2017

【vue2.0自定义事件】这一小节里面说的内容并不是,平行组件(非父子组件通信)间的通信,这一节写的仍然是父子间的通信吧。父与子A,父与子B间的通信,但是没有实现子A与子B间的通信

@webplus

This comment has been minimized.

Owner

webplus commented Mar 20, 2017

简单的理解为父子组件间的通讯使用Props传递数据,非父子间组件通信使用Event Bus也就是事件的机制。

@webplus

This comment has been minimized.

Owner

webplus commented Apr 7, 2017

子组件向父组件传值,第一张图应该较清楚了吧,就是Event的方式

@MrTenger

This comment has been minimized.

MrTenger commented May 18, 2017

这不是官网文档吗?

@zqinmiao

This comment has been minimized.

zqinmiao commented Aug 17, 2017

image
你好,如上图的这句话。也就是说,如果我的prop是一个object的话,那么我在子组件中使用this.object.xxx='xxx';的话,那么在父组件中也就可以获取到改变后的object里的xxx属性的值了。
请问,这种方式虽然是能达到预期的效果,那么是不是不推荐这样做呢?

@webplus

This comment has been minimized.

Owner

webplus commented Aug 18, 2017

是的

@webplus webplus added the vue.js label Nov 16, 2017

@MontageD

This comment has been minimized.

MontageD commented Mar 10, 2018

总结得挺清楚的。。

@MontageD

This comment has been minimized.

MontageD commented Mar 10, 2018

特别是子组件向父组件传递自定义事件那块

@itboos itboos referenced this issue Mar 22, 2018

Open

Vue相关 #12

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment