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 = valconsole.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.valueemit1('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.jsclass 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 = emitterapp.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>
其实试了下,两个都可以一起用。