8

众所周知,Vue 是基于组件来构建 web 应用的。组件将模块和组合发挥到了极致。Vue 是虽说吸取了 AngularJs 的 MVVM的思想,但是它是单向数据流的,也就是说子组件无法直接改变父组件状态。下面总结出常用的组件消息传递的方式。

父组件向子组件传递数据

该方式的数据传递是遵循 Vue 单向数据流的规则的,因此使用起来十分的自然。若父组件的数据改变子组件的 UI 展现也随之变化。
Parent.vue

<template>
  <div>
    <h1>Parent</h1>
    <child :name="childName" />
    <button @click="changeChildName">change the child name</button>
  </div>
</template>
<script>
import Child from './Child';

export default {
  components: {
    Child,
  },
  data() {
    return {
      childName: 'child name is what?',
    };
  },
  methods: {
    changeChildName() {
      this.childName = 'no name';
    },
  },
};
</script>

Child.vue

<template>
  <div>{{name}}</div>
</template>
<script>
export default {
  props: ['name'],
};
</script>

效果如下:
parent-child.gif

子组件修改父组件的数据

这里介绍两种方式:
1、子组件触发事件,父组件监听事件做出数据改变
2、父组件将数据变更方法以 props 的形式传给子组件(借鉴 react 的父子通信方式)

监听事件

父组件上通过 v-on 监听子组件所触发的事件。
EventParent.vue

<template>
  <div>
    <h1>Event Parent</h1>
    <child :name="childName" @changeParent="changeChildName" />
  </div>
</template>
<script>
import Child from './Child';

export default {
  components: {
    Child,
  },
  data() {
    return {
      childName: 'child name is what?',
    };
  },
  methods: {
    changeChildName() {
      this.childName = 'no name';
    },
  },
};
</script>

EventChild.vue

<template>
  <div>
    {{name}}
     <button @click="changeParentData">change the parent name</button>
  </div>
</template>
<script>
export default {
  props: ['name'],
  methods: {
    changeParentData() {
      this.$emit('changeParent');
    },
  },
};
</script>

效果如图:
event-parent-child.gif

传递props

因为自己写 react 较多,所以好奇 Vue 是否支持子组件回调父组件的事件处理函数,试了一下是可以的。好像 Element UI 使用该方式较多。个人认为该方法和事件方式同样灵活。
Parent.vue

<template>
  <div>
    <h1>Props Parent</h1>
    <child :name="childName" :changeName="changeChildName" />
  </div>
</template>
<script>
import Child from './Child';

export default {
  components: {
    Child,
  },
  data() {
    return {
      childName: 'child name is what?',
    };
  },
  methods: {
    changeChildName() {
      this.childName = 'no name';
    },
  },
};
</script>

Child.vue

<template>
  <div>
    <div>{{name}}</div>
    <button @click="changeName">Change Name</button>
  </div>
</template>
<script>
export default {
  props: ['name', 'changeName'],
};
</script>

props-parent-child.gif

以 props 的这种方式大家可以尝试实现一下是一种新的思路。

非父子组件间的通信

上述三个实例都在讲述父子组件的通信,那么不相关的组件该如何通信呢?可以创建一个 Vue 的实例作为来中转事件。
eventHub.js

import Vue from 'vue';

export default new Vue();

Child01.vue

<template>
  <div>
    <div>我是哥哥,我来触发事件</div>
    <button @click="clickButton">CLICK</button>
  </div>
</template>
<script>
import EventHub from './eventHub';

export default {
  methods: {
    clickButton() {
      EventHub.$emit('emitevent');
    },
  },
};
</script>

Child02.vue

<template>
  <div>
    <div>我是弟弟,我来监听哥哥触发的事件来改变自己的数据</div>
    <span>{{title}}</span>
  </div>
</template>
<script>
import EventHub from './eventHub';

export default {
  created() {
    EventHub.$on('emitevent', () => {
      this.title = 'Hi Brother';
    });
  },
  data() {
    return {
      title: 'Hello EveryOne~',
    };
  },
};
</script>

效果如图:
siblings-demo.gif

总结

父组件改变子组件的数据利用正常单向数据流的特性即可,子组件改变父组件的数据可以通过事件或者函数 props 两种方式实现,非父子组件通信则利用 EventHub 中转一下。

实例代码

欢迎大家指正批评、或留言。QQ群:538631558

【开发环境推荐】Cloud Studio 是基于浏览器的集成式开发环境,支持绝大部分编程语言,包括 HTML5、PHP、Python、Java、Ruby、C/C++、.NET 小程序等等,无需下载安装程序,一键切换开发环境。 Cloud Studio提供了完整的 Linux 环境,并且支持自定义域名指向,动态计算资源调整,可以完成各种应用的开发编译与部署。

亖混子
4.7k 声望2.4k 粉丝

自信、自洽、自在