vue组件中通信
Geek-James opened this issue · 0 comments
本文总结了vue组件间通信的几种方式,如props
、$emit/$on
、vuex
、$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