Vue2中父子组件通信的几种方式
发布于 3 年前 作者 yegang 3892 次浏览 来自 分享

Vue中父子组件通信规则是:父组件要给子组件传递数据,子组件需要将它内部发生的事情
告知给父组件。可以总结为:props down, events up.父组件向下传递数据给子组件,子组件通过events
给父组件发送消息。
如下图所示:

使用Prop传递数据(props down)

动态Prop

类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。
每当父组件的数据变化时,该变化也会传导给子组件:

<div>
  <input v-model="parentMsg">
  <br>
  <child :my-message="parentMsg"></child> <!-- v-bind:my-message="parentMsg"的缩写 -->
</div>

单向数据流

prop 是__单向绑定__的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。
另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。
这意味着你__不应该__在子组件内部改变 prop 。
通常有两种改变 prop 的情况:

  1. prop 作为初始值传入,子组件之后只是将它的初始值作为本地数据的初始值使用;
  2. prop 作为需要被转变的原始值传入。

Prop验证

组件可以为 props 指定验证要求。如果未指定验证要求,Vue 会发出警告。当组件给其他人使用时这很有用。
如下:

Vue.component('example', {
  props: {
    propA: {
      type: Object, // 验证类型
      default: function () { // 数组/对象的默认值应当由一个工厂函数返回
        return {message: 'hello'}
      }
    },
    propB: {
      validator: function (value) {
        return value > 10 // 自定义验证规则
      }
    }
  }
})

type 也可以是一个自定义构造器,使用 instanceof 检测。
当 prop 验证失败了,如果使用的是开发版本会抛出一条警告。

自定义事件(events up)

父组件使用props传递数据给子组件,而子组件用__自定义事件__把数据传递回去

使用v-on绑定自定义事件

每个Vue实例都实现了事件接口,即:

  • 使用 $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
    }
  }
})

子组件索引

尽管有 props 和 events ,但是有时仍然需要在 JavaScript 中直接访问子组件。
为此可以使用 ref 为子组件指定一个__索引 ID__ 。例如:

<div id="parent">
  <user-profile ref="profile"></user-profile>
</div>
var parent = new Vue({
  el: '#parent'
})
// 访问子组件
var child = parent.$ref.profile

当 ref 和 v-for 一起使用时, ref 是一个数组或对象,包含相应的子组件。

$refs 只在组件渲染完成后才填充,并且它是非响应式的。
它仅仅作为一个直接访问子组件的__应急方案__——应当避免在模版或计算属性中使用 $refs 。

非父子组件通信

有时候非父子关系的组件也需要通信。在简单的场景下,使用一个空的 Vue 实例作为中央事件总线:

var bus = new Vue()
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)
// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
  // ...
})

更为复杂的情况就应该考虑使用状态管理模式

参考资料

  1. Vue.js中文文档
1 回复

发布消息在手机看不到为什么

回到顶部