1. Vue Components' Communication by props and event

1.1. Parent to Child -- props

props 用于 parent component 发送到 child component。

App.vue:

<template>
  <app-child v-bind:msg="message"></app-child>
</template>

<script>
import Child from './components/Child.vue'

export default {
  components: {
    'app-child': Child
  },
  data() {
    return {
      message: 'hello'
    }
  }
}
</script>

Child.vue:

<template>
  <div>{{ msg }}</div>
</template>

<script>
  export default {
    // props: ['msg'],
    props: {
      'msg': {
        type: String,
        required: true
      }
    },

    data() {
      return {
      }
    }
  }
</script>

需要注意的点:

  1. Parent 使用 v-bind 进行 props 传递, Child 用 props 接收
  2. Child props 也可以完成 validation

1.2. primitive and reference types

  • primitive types: string, number, boolean
  • reference types: array, object

假设 Parent 传递的 props 是一个 array,这个 array 的 props 被多个 Child 使用,则在一个 Child 中进行修改 array,其实是修改了 data source,因为是通过引用传递的。这样其他 Child 的数据也会被改变。对数据共享来说是好事。Children 之间没有对 reference types 进行隔离。

如果 Parent 传递的 props 是 primitive types,一个 Child 修改只影响自身,其他 Child 不会被修改。如果希望数据同步,有这两做法:

  1. 被修改的 Child emit event,Parent 订阅这个 event,回调函数中修改属性,这样所以 Children 重新渲染
  2. 不通过 Parent,希望 Child2 直接关注 Child1 的状态,使用 event bus

1.3. Child to Parent -- Event

App.vue: 父级通过 v-on:子组件 emit 名字 = 回调函数 实现对子组件事件的订阅。回调函数进行数据处理。

<template>
  <div>
    <app-header v-bind:title="title" v-on:changeTitle="updateTitle($event)"></app-header>
    <app-footer v-bind:title="title"></app-footer>
  </div>
</template>

<script>
import Header from './components/Header.vue';
import Footer from './components/Footer.vue';

export default {
  components: {
    'app-header': Header,
    'app-footer': Footer
  },
  data () {
    return {
      title: 'Vue Wizards'
    }
  },
  methods: {
    updateTitle: function(updatedTitle){
      this.title = updatedTitle;
    }
  }
}
</script>

Header.vue: 子组件在某个函数中 emit 某个自定义事件和数据 -- this.$emit('changeTitle', 'Vue Ninjas');

<template>
  <h1 v-on:click="changeTitle">{{ title }}</h1>
</template>

<script>
export default {
    props: {
      title: {
        type: String,
        required: true
      }
    },
    data(){
      return{ }
    },
    methods: {
      changeTitle: function(){
        this.$emit('changeTitle', 'Vue Ninjas');
      }
    }
}
</script>

Footer.vue: 另一个子组件因为父级 title props 改变而重新渲染,数据也就改变了。

<template>
  <footer>
    <p>Copyright 2017 {{ title }}</p>
  </footer>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      required: true
    }
  },
  data(){
    return{
    }
  }
}
</script>

1.4. Event bus

Event bus is a vue instance.

main.js:

export const bus = new Vue();

Header.vue: 引起变化的子组件。

<template>
  <h1 v-on:click="changeTitle">{{ title }}</h1>
</template>

<script>
// 引入 event bus
import { bus } from '../main';

export default {
  props: {
    title: {
      type: String,
      required: true
    }
  },
  data(){
    return{
    }
  },
  methods: {
    changeTitle: function(){
      // 修改自己的 title 属性
      this.title = 'Vue Ninjas';
      // 向 bus emit 事件
      bus.$emit('titleChanged', 'Vue Ninjas');
    }
  }
}
</script>

Footer.vue: 关心 Header 的子组件。

<template>
  <footer>
    <p>Copyright 2017 {{ title }}</p>
  </footer>
</template>

<script>
// 引入 event bus
import { bus } from '../main';

export default {
  props: {
    title: {
      type: String,
      required: true
    }
  },
  data(){
    return{
    }
  },
  // 生命周期钩子,创建时候 bus 就订阅事件
  created(){
    bus.$on('titleChanged', (data) => {
      this.title = data;
    });
  }
}
</script>

1.5. 结合 react 的思考

Vue 的组件间通信简单说就是 props 和 event emit。子级 emit,父级订阅之并在回调函数中修改 props 数据,子级重新渲染。

react 父级向子级通信也是通过 props。子级向父级:子级某个函数调用 setState 去修改父级的 state,而这个 setState 也是通过 props 传递给子级的。react 可能需要把多个子级都需要的数据提取到父级 state 中。

Vue 子组件之间可以通过 Event bus 直接进行通信。React 单项数据流不推荐这种做法,但可以通过 context API 进行跨多个 level 组件间的 props 传输。

Copyright © Guanghui Wang all right reserved,powered by GitbookFile Modified: 2019-08-25 13:56:34

results matching ""

    No results matching ""