在使用vue时,我们经常会把不同的模块拆分成不同的组件,而组件之间有的需要传递数据,所以组件间的数据通信就非常重要了。
而在vue中,组件之间的关系大致可以分为以下两种:
父子组件之间通信
非父子组件之间通信(兄弟组件、祖孙组件等)
props/$emit
对于父子组件通信而言,最简单的方式就是 利用 props。 父组件可以通过props的方式向子组件传递数据,而子组件通过$emit可以向父组件通信。
父组件:
<template>
<div class="Father">
<ChildComponent :list="list" @changeList="changeList"/>
</div>
</template>
<script>
import ChildComponent from '../Son/SonComponent.vue'
import {ref} from 'vue';
const list = ref(['HTML','CSS','JS'])
export default {
name: 'FatherComponent',
components:{
ChildComponent
},
setup(){
function changeList(value){
list.value.push(value)
}
return {
list,
changeList
}
}
}
</script>
子组件:
<template>
<div class="Son">
<h1>This is Child</h1>
<ul>
<li v-for="item in list" :key="item.index">{
{item}}</li>
</ul>
<button @click="$emit('changeList','Python')"></button>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
props: {
list: Array,
},
setup(props){
console.log(props.list);
}
}
</script>
利用props将父组件数据传递给子组件
注意点:
1、props只可以从上一级组件传递到下一级组件(即父子组件),即所谓的单向数据流。【如有需要,可以通过data属性接收或使用computed属性进行转换】
2、props只读,不可被修改,所有修改都会失效并警告。
子组件想将数据传递给父组件时,使用 $emit触发自定义事件,父组件使用v-on(缩写为@)来监听事件
refs
父组件获取子组件的属性或者调用子组件方法
子组件:
<template>
<div class="Son">
<h1>{
{message}}</h1>
</div>
</template>
<script setup>
import { ref, defineExpose } from 'vue'
let message = ref('I am Child')
const showMessage = () => {
alert('123')
}
defineExpose({
message,
showMessage
})
</script>
父组件:
<template>
<div class="Father">
<ChildComponent ref="child"></ChildComponent>
<button @click="show">Show Child Message</button>
</div>
</template>
<script setup>
import ChildComponent from '../Son/SonComponent.vue'
import {ref} from 'vue';
const child = ref()
const show = () =>{
console.log(child.value.message);
child.value.showMessage();
}
</script>
3. provide/inject
provide/inject 是 Vue中提供的一对API。无论层级多深,API都可以实现父组件到子孙组件的数据传递。
provide:提供一个值,可以被后代组件注入
inject: 注入一个由祖先组件或整个应用提供的值
父组件:
<template>
<div class="Father">
</div>
</template>
<script setup>
import {provide} from 'vue'
provide('eric','eric_content')
</script>
子组件:
<template>
<div class="Son">
<h1>{
{message}}</h1>
</div>
</template>
<script setup>
import { inject } from 'vue'
let message = inject('eric')
console.log(message);
</script>
4. eventBus
eventBus,又称事件总线,其原理就是 事件订阅发布。在vue中可以使用它来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以通知其他组件。
但是vue3中移除了eventBus,但是可以借助第三方工具,如mitt来实现。其原理还是eventBus
使用步骤:
安装:
cnpm i mitt -S
封装:
import mitt from 'mitt'
const mitt = mitt()
export default mitt
使用:
组件1:
<template>
<div class="component1">
<button @click="handleClick">click</button>
</div>
</template>
<script setup>
import bus from '../mitt'
const handleClick = () => {
bus.emit('handleChange','eric')
}
</script>
组件2:
<template>
<div class="component2">
123
</div>
</template>
<script setup>
import bus from '../mitt'
import { onMounted, onUnmounted } from 'vue'
onMounted(()=>{
bus.on('handleChange',(info)=>{
console.log(info);
alert(123)
})
})
onUnmounted(()=>{
bus.off('handleChange',someMethod)
})
</script>
5. vuex/Pinia
Vuex 和 Pinia 是 Vue 3 中的状态管理工具,使用这两个工具可以轻松实现组件通信