Vue组件通讯的几种方式

父组件经过 Prop 向子组件传递数据

这个数据流是单向的。数据流向是从父组件传到子组件。也就是说,父级 prop 的更新会向下流动到子组件中,可是反过来则不行。
如今咱们须要写一个博文组件,展现博文的标题和内容。标题和内容这些数据是从父组件得到的。
第一步,定义一个组件,这里用注册全局组件的方式,子组件用prop接收来自父组件的数据:html

Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h2>{{ post.title }}</h2>
      <div v-html="post.content"></div>
    </div>
  `
});

第二步,初始化一个Vue实例并挂载到对应的HTML结构:vue

// html
<div id="app">
  <blog-post :post="post" v-for="(post, index) in postArr" :key="index"></blog-post>
</div>

// js
new Vue({
  el: "#app",
  data: {
    postArr: [
      {
          title: 'My name is Judy',
        content: 'something here '
      },
      {
          title: 'My job is coding',
        content: 'something here '
       },
       {
            title: 'I like coding',
          content: 'something here '
       }
    ]
  }
});

demo:父组件经过 Prop 向子组件传递数据vuex

子组件经过事件向父级组件发送消息

在咱们开发 <blog-post> 组件时,它的一些功能可能要求咱们和父级组件进行沟通。例如咱们可能会引入一个可访问性的功能来放大博文的字号,同时让其余部分的博文保持默认的字号。
仍是刚才那个demo,在其父组件中,咱们能够经过给每一条博文的数据添加一个 postFontSize 数据属性来控制每篇博文字体的大小。app

// js
new Vue({
  el: "#app",
  data: {
    postArr: [
      {
        postFontSize: 1,
          title: 'My name is Judy',
        content: 'something here '
      },
      {
        postFontSize: 1,
          title: 'My job is coding',
        content: 'something here '
      },
      {
        postFontSize: 1,
        title: 'I like coding',
        content: 'something here '
      }
    ]
  }
});

如今咱们须要给子组件添加一个按钮。当点击这个按钮时,咱们须要告诉父级组件放大全部博文的文本。恰好 Vue 实例提供了一个自定义事件的系统来解决这个问题。咱们能够调用内建的 $emit 方法并传入事件的名字,来向父级组件触发一个事件。改写一会儿组件:ide

Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h2>{{ post.title }}</h2>
      <button @click="$emit('enlarge-text')">
        Enlarge text
      </button>
      <div v-html="post.content"></div>
    </div>
  `
});

而后咱们能够用 v-on 在博文组件上监听这个事件,就像监听一个原生 DOM 事件同样:post

<div id="app">
  <blog-post 
    @enlarge-text="post.postFontSize += 0.1" 
    :post="post" 
    v-for="(post, index) in post_arr" 
    :key="index"
    :style="{ fontSize: post.postFontSize + 'em' }"
  ></blog-post>  
</div>

demo:子组件经过事件向父级组件发送消息字体

以上为经常使用的父组件向子组件传递数据、子组件经过事件向父级组件发送消息的两种方式。ui

$parent访问父级组件实例

$parent 属性能够用来从一个子组件访问父组件的实例。它提供了一种机会,能够在后期随时触达父级组件,以替代将数据以 prop 的方式传入子组件的方式,实际上这不是一种数据传递,而是子组件主动发起的数据查找。
可是Vue并不推荐这么作。在绝大多数状况下,触达父级组件会使得咱们的应用更难调试和理解,尤为是咱们变动了父级组件的数据的时候。当咱们稍后回看那个组件的时候,很难找出那个变动是从哪里发起的。
在一些可能适当的时候,咱们须要特别地共享一些组件库,就能够考虑用$parent。Vue官网称这些状况为【边界状况】。
假设有一个Google地图组件:this

<google-map>
  <google-map-markers v-bind:places="iceCreamShops"></google-map-markers>
</google-map>

这个 <google-map> 组件能够定义一个 map 属性,全部的子组件都须要访问它。在这种状况下 <google-map-markers> 能够经过相似 this.$parent.getMap 的方式访问那个地图,以便为其添加一组标记。
点击这里查看官方文档给出的demogoogle

ref 特性访问子组件实例或子元素

尽管存在 prop 和事件,有的时候仍可能须要在 JavaScript 里直接访问一个子组件。为了达到这个目的,咱们能够经过 ref 特性为这个子组件赋予一个 ID 引用。
例如:

<base-input ref="usernameInput"></base-input>

如今在已经定义了这个 ref 的组件里就可使用:

this.$refs.usernameInput

来访问这个 <base-input> 实例,以便不时之需。
另外,vm.$children也能够访问当前实例的直接子组件。须要注意 $children 并不保证顺序,也不是响应式的。

当咱们须要访问子组件或者子元素,推荐使用 ref 而不是 $children
由于 ref 能帮咱们访问到的是任意子组件实例或者子元素,$children 只能访问到直接子组件

Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
什么意思呢?在实际开发中,咱们会遇到有一处或者多处须要被多个实例间共享的状态,Vuex就是为咱们提供了这样一个模式。因此个人理解是Vuex不只仅是适用于父子组件的通讯了,它适用于全部组件共享某些必要的数据状态。
关于Vuex的使用咱们这里不详细展开讨论了,贴一个Vuex的文档地址

一些补充

前面咱们提到google地图组件,相似这样的:

<google-map>
  <google-map-region v-bind:shape="cityBoundaries">
    <google-map-markers v-bind:places="iceCreamShops"></google-map-markers>
  </google-map-region>
</google-map>

在这个组件里,全部 <google-map> 的后代都须要访问一个 getMap 方法,以便知道要跟那个地图进行交互。不幸的是,使用 $parent 属性没法很好的扩展到更深层级的嵌套组件上,也就是说,只有<google-map-region>能经过 $parent 访问到它的直接父组件<google-map>的 getMap 方法。这种状况能够用依赖注入 provideinject 解决。

provide 选项容许咱们指定咱们想要提供给后代组件的数据/方法。在这个例子中,就是 <google-map> 内部的 getMap 方法:

provide: function () {
  return {
    getMap: this.getMap
  }
}

而后在任何后代组件里,咱们均可以使用 inject 选项来接收指定的咱们想要添加在这个实例上的属性:

inject: ['getMap']

点击这里查看官方文档的demo

相比 $parent 来讲,这个用法可让咱们在任意后代组件中访问 getMap,而不须要暴露整个 <google-map> 实例。这容许咱们更好的持续研发该组件,而不须要担忧咱们可能会改变/移除一些子组件依赖的东西。同时这些组件之间的接口是始终明肯定义的,就和 props 同样。

实际上,你能够把依赖注入看做一部分“大范围有效的 prop”,除了:

  • 祖先组件不须要知道哪些后代组件使用它提供的属性
  • 后代组件不须要知道被注入的属性来自哪里

我看了不少篇总结Vue父子组件通讯方式的博客都没有提到依赖注入,不过我以为依赖注入也实现了通讯——由父组件经过 provide 把数据暴露出去,子组件经过 inject 接收数据。

以上就是我阅读官方文档总结出来的Vue组件通讯的几种方式,大部份内容和demo都来源于官网文档,了解更多能够阅读文档:Vue文档地址。文章所有内容仅表明我的观点,欢迎批评或者与我讨论。感谢你的阅读。

相关文章
相关标签/搜索