vue3学习记录-组件通信
- 1.父子组件通信
- 2.兄弟组件传值
- 2.1 以父组件为媒介
- 2.2 发布订阅模式
- 2.3 使用mitt
- 2.3.1 全局使用
- 2.3.2 局部使用
1.父子组件通信
父组件:
<template>
父组件原有的title:{{ title }}
<p>---</p>
<com :title="title" :flag="true" @changeTitle="changeTitle"></com>
</template>
<script setup>
import { computed, ref } from 'vue'
import com from './components/com.vue'
let title = ref('我是标题')
function changeTitle(newTitle){
title.value = newTitle
}
</script>
<style></style>
子组件:
<template>
<div>
我是子组件
<p>子组件的title:{{ title }}</p>
<button @click="changeTitle1">我要给父组件传参</button>
</div>
</template>
<script setup>
defineProps({
title: {
default: '',
type: String
},
flag: Boolean
})
const emit1 = defineEmits(['changeTitle'])
function changeTitle1() {
emit1('changeTitle', '我是子组件传给父组件的参数')
}
//子传父事件
//1.const emit1 = defineEmits(['changeTitle'])定义emit
//2.直接在事件后 emit1('changeTitle', '我是子组件传给父组件的参数'),然后父组件接收
</script>
<style lang="scss" scoped></style>
defineProps父传子定义,defineEmits子传父定义
2.兄弟组件传值
2.1 以父组件为媒介
//App.vue
<script setup>
import A from './components/A.vue';
import B from './components/B.vue';
import { ref } from 'vue';
const mainFlag = ref(false)
const clickEvent1 = (val) => {
mainFlag.value = val
console.log('clickEvent', val);
};
</script>
<template>
<A @clickEvent="clickEvent1"></A>
<B :mainFlag="mainFlag"></B>
</template>
<style scoped></style>
//A.vue
<template>
<div class="container">
<p>我是A组件
</p>
<el-button @click="clickEvent1">分发事件</el-button>
</div>
</template>
<script setup>
import { ref, reactive} from 'vue'
const flag = ref(false)
const clickEvent1 = () =>{
flag.value =!flag.value
emit1('clickEvent',flag.value)
}
const emit1 = defineEmits(['clickEvent'])
</script>
<style lang='scss' scoped>
.container{
width: 200px;
height: 200px;
background-color: lightcoral;
margin-bottom: 10px;
}
</style>
//B.vue
<template>
<div class="container">
<p>我是B组件</p>
{{ mainFlag }}
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
defineProps({
mainFlag: {
type: Boolean,
required: true
}
})
</script>
<style lang='scss' scoped>
.container {
width: 200px;
height: 200px;
background-color: lightblue;
}
</style>
A组件分发事件给父组件,父组件再把值传给B组件。这样是可以的,但是写法不太简易,层级多了就要递传。
2.2 发布订阅模式
// eventBus.js
class EventBus {
constructor() {
this.events = new Map();
}
// 订阅事件
on(eventName, callback) {
if (!this.events.has(eventName)) {
this.events.set(eventName, []);
}
this.events.get(eventName).push(callback);
}
// 取消订阅
off(eventName, callback) {
if (!this.events.has(eventName)) return;
const callbacks = this.events.get(eventName);
const index = callbacks.indexOf(callback);
if (index !== -1) {
callbacks.splice(index, 1);
}
}
// 发布事件
emit(eventName, ...args) {
const callbacks = this.events.get(eventName) || [];
callbacks.forEach(callback => callback(...args));
}
}
export default new EventBus();
2.3 使用mitt
安装依赖
npm install mitt
2.3.1 全局使用
//main.js
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import mitt from 'mitt'
const emitter = mitt()
const app = createApp(App)
app.config.globalProperties.$EventBus = emitter
app.mount('#app')
<!-- ComponentA.vue -->
<script setup>
import { ref,getCurrentInstance } from 'vue'
const message = ref('')
const { proxy } = getCurrentInstance()
const sendMessage2 = () => {
proxy.$EventBus.emit('new-message', message.value)
message.value = ''
}
onBeforeUnmount(() =>{
proxy.$EventBus.off('new-message')
})
</script>
<template>
<div>
<input v-model="message" placeholder="输入消息" />
<button @click="sendMessage2">发送消息2</button>
</div>
</template>
<!-- ComponentB.vue -->
<script setup>
import { ref, onMounted, onUnmounted,getCurrentInstance } from 'vue'
const receivedMessages = ref([])
const {proxy} = getCurrentInstance()
const onNewMessage = (msg) => {
receivedMessages.value.push(msg)
}
onMounted(() => {
proxy.$EventBus.on('new-message', onNewMessage)
})
onUnmounted(() => {
proxy.$EventBus.off('new-message', onNewMessage)
})
</script>
<template>
<div>
<h2>接收到的消息:</h2>
<ul>
<li v-for="(msg, index) in receivedMessages" :key="index">{{ msg }}</li>
</ul>
</div>
</template>
2.3.2 局部使用
// eventBus.js
import { ref } from 'vue'
import mitt from 'mitt'
const emitter = mitt()
const bus = ref(emitter)
export default bus
<!-- ComponentA.vue -->
<script setup>
import { ref, getCurrentInstance, onBeforeUnmount } from 'vue'
import bus from '../eventBus'
const message = ref('')
const { proxy } = getCurrentInstance()
const sendMessage = () => {
bus.value.emit('new-message', message.value)
message.value = ''
}
const sendMessage2 = () => {
proxy.$EventBus.emit('new-message', message.value)
message.value = ''
}
onBeforeUnmount(
() => {
proxy.$EventBus.off('new-message')
bus.value.off('new-message')
}
)
</script>
<template>
<div>
<input v-model="message" placeholder="输入消息" />
<button @click="sendMessage">发送消息</button>
<button @click="sendMessage2">发送消息2</button>
</div>
</template>
<!-- ComponentB.vue -->
<script setup>
import { ref, onMounted, onUnmounted,getCurrentInstance } from 'vue'
import bus from '../eventBus'
const receivedMessages = ref([])
const {proxy} = getCurrentInstance()
const onNewMessage = (msg) => {
receivedMessages.value.push(msg)
}
onMounted(() => {
proxy.$EventBus.on('new-message', onNewMessage)
bus.value.on('new-message', onNewMessage)
})
onUnmounted(() => {
proxy.$EventBus.off('new-message', onNewMessage)
bus.value.off('new-message', onNewMessage)
})
</script>
<template>
<div>
<h2>接收到的消息:</h2>
<ul>
<li v-for="(msg, index) in receivedMessages" :key="index">{{ msg }}</li>
</ul>
</div>
</template>
其实试了下,两个都可以一起用。