Geek-James/Blog

vue组件中通信

Geek-James opened this issue · 0 comments

本文总结了vue组件间通信的几种方式,如props$emit/$onvuex$parent / $children$attrs/$listeners和provide/inject,以通俗易懂的实例讲述这其中的差别及使用场景,希望对小伙伴有些许帮助。

组件之间通信是Vue中最常用,最基础的部分,通常组件之前的通信分为以下几种:

  • 1.父组件给子组件以及子子组件传递值,传递事件
  • 2.子组件给父组件传递值,传递事件
  • 3.兄弟组件之间传递值,传递事件

方法一、props/$emit

1.父组件给子组件传值

父组件A通过props的方式向子组件B传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现。

子组件使用this.$emit('function',param)向父组件传值

父组件通过v-on:function="function"来接受子组件传递过来的值

接下来我们通过一个例子来加深以上理解:

自定义一个Son.vue子组件,引入到父组件中
在父组件中定义一个数据

<template>
    <div id="app">
        <!-- 前者自定义名称便于子组件调用,后者要传递数据名 -->
        <son v-bind:user="user"></son>  
    </div>
</template>
<script>
import Son from './components/Son'

export default {
    name: 'app',
    components: {
        Son,
    },
    data () {
        return { // 父组件定义数据,传递给子组件
            user: ["james", "alice", "joho"]
        }
    },
  }
</script>
    

子组件中通过prop来定义父组件传值的值类型,是否是必须以及默认值

<script>
export default {
    components: {

    },
    data () {
        return {

        };
    },
    computed: {

    },
    methods: {
    },
    props: {
        user: { //这个就是父组件中子标签自定义名字
            type: Array,
            required: true,
            default: []
        }
    },
}
</script>

然后在适当的位置将父组件传递过来的数据进行渲染

<template>
    <div>
        <ul>
            <li v-for="(item,index) in user"
                :key="index">姓名:{{item}}</li>
        </ul>

    </div>
</template>

浏览器打开会显示user里面的值.

总结:父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed

2.子组件向父组件传值(通过事件形式)

我们通过一个案例来说明子组件是如何给父组件传递值的,点击子组件的按钮,子组件向父组件传递值,然后改变父组件里文字的值.

子组件中:

子组件包含一个点击事件

// 定义一个点击事件
 <son v-bind:user="user"
             @titleChange="changeTitle">
</son>

在点击事件中通过this.$emit()来传递事件

<script>
//import x from ''
export default {
    components: {

    },
    data () {
        return {
            title: '我是子组件',
            toParentData: '我是子组件传递的数据'
        };
    },
    computed: {

    },
    methods: {
        btnClick () {
            this.$emit('titleChange', this.toParentData);
        }
    },
    }
</script>

父组件中:
通过v-on来接受子组件发出的事件名称:titleChange并且和自己的changeTitle事件绑定

<template>
    <div id="app">
        <!-- 前者自定义名称便于子组件调用,后者要传递数据名 -->
        <son v-bind:user="user"
             v-on:titleChange="changeTitle"></son>
        <p>{{msg}}</p>
    </div>
</template>

实现changeTitle方法,改变data中的msg数据

<script>
import Son from './components/Son'

export default {
    name: 'app',
    components: {
        Son,
    },
    data () {
        return {
            user: ["james", "alice", "joho"],
            msg: '我是父组件显示的内容'
        }
    },
    methods: {
        changeTitle (title) {
            this.msg = title;
        }
    }
}
</script>

总结:子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。

**事件总线 Bus 进行通信

子孙的链式通信显然会使得组件紧耦合,同时兄弟组件间的通信该如何实现呢?这里介绍**事件总线的方式,实际上就是用一个vue实例(Bus)作为媒介,需要通信的组件都引入 Bus,之后通过分别触发和监听 Bus 事件,进而实现组件之间的通信和参数传递。

  • 1.首先建 Vue 实例作为总线:
// Bus.js
import Vue from 'vue'
export default new Vue;
  • 2.需要通信的组件都引入 Bus.js,使用 $emit发送信息:
// ComponentA.vue
<template>
  <div>
    <b>组件A:</b><button @click="handleBus">传递数值给需要的组件</button>
  </div>
</template>

<script>
  import Bus from './bus.js' 
  export default {
    methods: {
      handleBus () {
        Bus.$emit('someBusMessage','来自ComponentA的数据')
      }
    }
  }
</script>
  • 3.需要组件A信息的就使用$on来监听:
// ComponentB.vue
<template>
  <div>
    <b>组件B:</b><button @click="handleBus">接收组件A的信息</button>
    <p>{{message}}</p>
  </div>
</template>

<script>
  import Bus from './bus.js' 
  export default {
    data() {
      return {
        message: ''
      }
    },
    created () {
      let that = this // 保存当前对象的作用域this
      Bus.$on('someBusMessage',function (data) {
        that.message = data
      })
    },
    beforeDestroy () {
      // 手动销毁 $on 事件,防止多次触发
      Bus.$off('someBusMessage', this.someBusMessage)
    }
  }
</script>

常见使用场景可以分为三类:

  • 父子通信:
    父向子传递数据是通过 props,子向父是通过 events($emit);
    通过父链 / 子链也可以通信($parent / $children);ref 也可以访问组件实例;provide / inject API;$attrs/$listeners
  • 兄弟通信:
    Bus;Vuex
  • 跨级通信:
    Bus;Vuex;provide / inject API、$attrs/$listeners

参考资料:https://juejin.im/post/5cde0b43f265da03867e78d3