介绍
首先组件作为vue.js最强大的功能之一,而且组件实例的作用域都是相互独立的,所以不同组件之间的数据无法相互进行直接的引用,因此组件间的相互通信是非常重要的。
这里介绍几种常见的通信方式:
父子之间
子父之间
兄弟之间
其他通信方式
父传子
在父组件中,用 v-bind 动态绑定一个自定义属性,用于给子组件传递数据
父组件
<template>
<div>
<child :users="user"></child>
</div>
</template>
<script>
import { child } from "./child";
export default {
components: { child },
data() {
return {
user: '李四'
};
}
};
</script>
在子组件中,使用 props 接收父组件传过来的数据。
<template>
<div>{
{ users }}</div>
</template>
<script>
export default {
props: ["users"]
};
</script>
子传父
子组件通过事件的方式,利用 $emit 给父组件传值。
注意:$emit 的第一个参数是父组件自定义事件的方法名,后边的 “value” 是子组件要给父组件传递的数据
子组件
<template>
<div>
<button @click="datas"></button>
</div>
</template>
<script>
export default {
methods: {
datas() {
this.$emit("info", value);
}
}
};
</script>
在父组件中,绑定一个自定义事件,用来接收子组件传来的值;
<template>
<div>
<child @info="getInfo"></child>
</div>
</template>
<script>
import { child } from "./child";
export default {
components: { child },
methods: {
getInfo(value) {
// value 就是子组件传递过来的数据
}
}
};
</script>
兄弟之间
eventBus事件总线适用于任意两个组件之间的通信,使用步骤如下:
// 方法一:
// 创建一个单独的 js文件 EventBus.js,然后在需要的地方引入
// EventBus.js
import vue from "vue"
ecport default new Vue()
// 方法二:
// 直接挂载在全局
// main.js
import vue from "vue"
Vue.prototype.$EventBus = new Vue()
// 方法三:
// 注入到Vue 跟对象上
// main.js
import vue from "vue"
new Vue ({
el:"#app",
data:{
EventBus:new Vue()
}
})
在需要发送的组件中发送事件:
<template>
<div>
<button @click="add">加法</button>
</div>
</template>
<script>
import {EventBus} from './EventBus.js' // 引入事件中心
export default {
data(){
return{
num:0
}
},
methods:{
add(){
EventBus.$emit('addition', {
num:this.num++
})
}
}
}
</script>
在接收组将中接收
<template>
<div>求和: {
{count}}</div>
</template>
<script>
import { EventBus } from './EventBus.js'
export default {
data() {
return {
count: 0
}
},
mounted() {
EventBus.$on('addition', param => {
this.count = this.count + param.num;
})
},
beforeDestory(){
// 取消监听
EventBus.off("addition")
}
}
</script>
用 $emit去监听,用$on去触发,注意需要$off来取消监听,否则可能会造成内存泄漏。
ref / $refs
这种方式也是实现父子组件之间的通信
ref:这个属性用在子组件上,它的用用就指向了子组件的实例,可以通过实例来访问组件的数据和方法
在子组件中:
export default {
data () {
return {
name: 'JavaScript'
}
},
methods: {
sayHello () {
console.log('hello')
}
}
}
在父组件中
<template>
<child ref="child"></component-a>
</template>
<script>
import child from './child.vue'
export default {
components: { child },
mounted () {
console.log(this.$refs.child.name); // JavaScript
this.$refs.child.sayHello(); // hello
}
}
</script>
$parent / $children
使用$parent可以让组件访问父组件的实例(访问的是上一级父组件的属性和方法)。
使用 $children 可以让组件访问子组件的实例,但是, $children 并不能保证顺序,并且访问的数据也不是响应式的。
注意:仅限于父子组件之间,不推荐使用,因为不利于维护,一旦组件层次发生了变化,就需要更改其中的层次关系
子组件中:
<template>
<div>
<span>{
{message}}</span>
<p>获取父组件的值为: {
{parentValue}}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Vue'
}
},
computed:{
parentVal(){
return this.$parent.parentMsg;
}
}
}
</script>
父组件中:
<template>
<div class="hello_world">
<div>{
{msg}}</div>
<child></child>
<button @click="change">点击改变子组件值</button>
</div>
</template>
<script>
import child from './child.vue'
export default {
components: { child },
data() {
return {
parentMsg: 'Welcome'
}
},
methods: {
change() {
// 获取到子组件
this.$children[0].message = 'JavaScript'
}
}
}
</script>
在上面的代码中,子组件获取到了父组件的parentValue值,父组件改变了子组件中message的值。
依赖注入(provide / inject)
这种方式就是vue中依赖注入,该方法用于 父子组件之间 的通信。当然这里所说的父子不一定是真正的父子,也可以是祖孙组件,在层数很深的情况下,可以使用这种方式来进行传值。就不用一层一层的传递数据了。
provide和inject是vue提供的两个钩子,和data、methods是同级的。并且provide的书写形式和data一样。
provide 钩子用来发送数据或方法。
inject钩子用来接收数据或方法
// 父组件
exportdefault{
provide(){
return {
message:'hellow world !'
}
}
}
// 后代组件
export default{
inject:['message']
}
缺陷:传递的数据不是响应式的,inject接收到数据后,provide中的数据改变,但是后代组件中的数据不会改变。所以 建议传一些常量或者方法。