Vue2.0组件之间的通信方式
「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。
一、props & $emit
props
和$emit
大概是我们平时用的最多的方式把。父组件向子组件传值采用prop
来传递,子组件则用$emit
通过事件触发的方式来传递。
父组件
<template>
<div>
<div class="parent">
<div>我是父组件</div>
<div>{{sonMsg}}</div>
<SonCom :msg="msg" @onSonSay="onSonSay"></SonCom>
</div>
</div>
</template>
<script>
import SonCom from './SonCom.vue'
export default {
components: { SonCom },
data() {
return {
msg: '我是你爸爸',
sonMsg: ''
}
},
methods: {
onSonSay(val) {
this.sonMsg = val
}
},
}
</script>
<style>
.parent {
width: 500px;
height: 150px;
border: 1px solid red;
}
</style>
子组件
<template>
<div class="son">
<div>我是子组件</div>
<div>
父组件对子组件说 {{msg}}
</div>
<button @click="handleClick">子组件说</button>
</div>
</template>
<script>
export default {
data() {
return {
}
},
props: {
msg: {
type: String
}
},
methods: {
handleClick() {
this.$emit('onSonSay', '你是我爸爸,你给钱我花啊!')
}
},
}
</script>
<style>
.son {
width: 500px;
height: 150px;
border: 1px solid green;
}
</style>
二、ref
我们在父组件里面引入的子组件上面设置ref
来获取到组件里面的属性和方法。
<div @click="onGetSonMsgOnRef">点击我,通过ref来访问子组件数据:{{getSonMsgOnRef}}</div>
<SonCom ref="sonComRef" :msg="msg" @onSonSay="onSonSay"></SonCom>
onGetSonMsgOnRef() {
this.getSonMsgOnRef = this.$refs.sonComRef.sonMsg
}
三、$parent
& $children
- 子组件通过访问
$parent
来获取父组件的信息
<div @click="() => parentMsg = $parent.msg">点击我,通过$parent拿到父组件的数据:{{parentMsg}}</div>
- 父组件通过
$children
来访问子组件的信息。
<div @click="() => childrenMsg = $children[0].sonMsg">点击我,通过$children拿到子组件的数据:{{childrenMsg}}</div>
四、provide & inject
provide
和 inject
可以实现祖孙组件间的通信。祖先组件中通过provider
来提供变量,然后在子孙组件中通过inject
来注入变量。
新建一个GrandsonCom
组件
<template>
<div>
<h3>{{grandson}}</h3>
<div>我通过inject拿到爷爷组件信息:{{name}}</div>
</div>
</template>
<script>
export default {
data() {
return {
grandson: '我是孙子组件'
}
},
inject: ['name']
}
</script>
在ParentCom
组件中引入孙子组件以及
provide: {
name: 'parent的数据'
},
五、$attrs
和 $listeners
$attrs
和 $listeners
也是可以实现祖孙组件间通信,当组件嵌套过深且中间组件不需要时,可以使用该方式。
-
$attrs
包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class
和style
除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class
和style
除外),并且可以通过v-bind="$attrs"
传入内部组件——在创建高级别的组件时非常有用。 -
$listeners
包含了父作用域中的 (不含.native
修饰器的)v-on
事件监听器。它可以通过v-on="$listeners"
传入内部组件——在创建更高层次的组件时非常有用。
ParentCom.vue
<template>
<div>
<div class="parent">
<div>我是父组件</div>
<div>{{sonMsg}}</div>
<div @click="onGetSonMsgOnRef">点击我,通过ref来访问子组件数据:{{getSonMsgOnRef}}</div>
<div @click="() => childrenMsg = $children[0].sonMsg">点击我,通过$children拿到子组件的数据:{{childrenMsg}}</div>
<SonCom ref="sonComRef" :msg="msg" :attrs1="attrs1" :attrs2="attrs2" :attrs3="attrs3"
@onSonSay="onSonSay" v-on:onListeners1="onListeners1" v-on:onListeners2="onListeners2" v-on:onListeners3="onListeners3"
></SonCom>
<!-- <GrandsonCom></GrandsonCom> -->
</div>
</div>
</template>
<script>
import SonCom from './SonCom.vue'
// import GrandsonCom from './GrandsonCom.vue'
export default {
components: { SonCom },
provide: {
name: 'parent的数据'
},
data() {
return {
msg: '我是你爸爸',
sonMsg: '',
childrenMsg: '',
getSonMsgOnRef: '',
attrs1: 'attrs1',
attrs2: 'attrs2',
attrs3: 'attrs3'
}
},
methods: {
onSonSay(val) {
this.sonMsg = val
},
onGetSonMsgOnRef() {
this.getSonMsgOnRef = this.$refs.sonComRef.sonMsg
},
onListeners1() {
console.log(111, 'onListeners1')
},
onListeners2() {
console.log(222, 'onListeners2')
},
onListeners3() {
console.log(333, 'onListeners3')
}
},
}
</script>
<style>
.parent {
width: 500px;
min-height: 150px;
border: 1px solid red;
}
</style>
SonCom.vue
<template>
<div class="son">
<div>我是子组件</div>
<div>
父组件对子组件说 {{msg}}
</div>
<button @click="handleClick">子组件说</button>
<div @click="() => parentMsg = $parent.msg">点击我,通过$parent拿到父组件的数据:{{parentMsg}}</div>
<div>父组件$attrs来的 {{attrs1}}</div>
<!-- v-bind="$attrs"通常和interitAttrs 选项一起使用 -->
<GrandsonCom v-bind="$attrs" v-on="$listeners"></GrandsonCom>
</div>
</template>
<script>
import GrandsonCom from './GrandsonCom.vue'
export default {
components: { GrandsonCom },
data() {
return {
sonMsg: '我是子组件里面的数据',
parentMsg: ''
}
},
inheritAttrs: false,
props: {
msg: {
type: String
},
attrs1: {
type: String
}
},
methods: {
handleClick() {
console.log(this.$parent)
this.$emit('onSonSay', '你是我爸爸,你给钱我花啊!')
}
},
mounted() {
this.$emit('onListeners1')
},
}
</script>
<style>
.son {
width: 500px;
min-height: 150px;
border: 1px solid green;
}
</style>
GrandsonCom.vue
<template>
<div>
<h3>{{grandson}}</h3>
<div>我通过inject拿到爷爷组件信息:{{name}}</div>
<div>爷爷组件来的attrs: {{attrs2}} </div>
</div>
</template>
<script>
export default {
data() {
return {
grandson: '我是孙子组件'
}
},
inject: ['name'],
props: ['attrs2'],
mounted() {
console.log('grandson attrs', this.$attrs)
this.$emit('onListeners2')
},
}
</script>
六、事件总线EventBus
首先我们创建一个event-bus.js
文件
import Vue from 'vue'
export const EventBus = new Vue()
然后我们创建一个OtherCom.vue
文件,并在在App.vue文件中引入
<template>
<div>
<div>{{msg}}</div>
<div>{{eventBusMsg}}</div>
</div>
</template>
<script>
import { EventBus } from "../event-bus.js";
export default {
data() {
return {
msg: '我是一个毫无关系的组件',
eventBusMsg: ''
}
},
mounted() {
EventBus.$on('onEventBus', (msg) => {
this.eventBusMsg = msg
})
},
}
</script>
我们在ParentCom.vue
中引入event-bus.js
文件,添加如下代码
<button @click="onSendMsg">发送公共消息</button>
onSendMsg() {
EventBus.$emit('onEventBus', '来自父组件的消息');
}
点击父组件页面发送公共消息按钮,会看到'来自父组件的消息'在页面上显示出来。
你可以使用 EventBus.$off('onEventBus')
来移除应用内所有对此某个事件的监听。或者直接调用 EventBus.$off()
来移除所有事件频道,不需要添加任何参数 。
七、vuex
vuex也可以实现跨组件通信,这里就不多说了,后面也会更新vuex相关的文章。
八、本地缓存的方式
可以使用localStorage 和 sessionStorage,可以实现跨组件通信。
转载自:https://juejin.cn/post/7067083542743744525