[英]Vue 3: Emit event from parent to child component
现在我需要从父组件向子组件发出事件。 我在 vue 版本 3 中看到$on
、 $off
和$once
实例方法被删除。 应用程序实例不再实现事件发射器接口。
现在如何在 vue 版本 3 中从父组件发出事件并从子组件监听?
您不会从子组件中侦听父事件,而是将道具向下传递给子组件,如果子组件需要更新数据,您将从子组件向父组件发出事件以更新 state。
只读生命周期:Parent > Prop > Child
读取/更新生命周期:Parent > Prop > Child > Emit > Parent > Update > Child Updates
您可以使用Refs
访问子方法
https://v3.vuejs.org/guide/composition-api-template-refs.html
<!-- Parent -->
<template>
<ChildComponent ref="childComponentRef" />
</template>
<script>
import { ref } from 'vue'
import ChildComponent from './components/ChildComponent.vue'
export default {
setup( ) {
const childComponentRef = ref()
childComponentRef.value.expandAll();
}
}
</script>
<!-- Child -->
<script>
export default {
setup() {
const expandAll= () => {
//logic...
}
return { expandAll}
}
}
</script>
如果您像我一样在 Vue2 中的this.$root.$on(...)
和this.$root.$emit(...)
上调用一些事件,从任何父/子到任何子/父,以某种方式保持您的代码清理器,而不是分别使用一堆发射和道具,让你的代码炸毁..
从 Vue3 文档,事件总线模式可以通过使用实现事件发射器接口的外部库来替换。 使用实现 pub-sub 模式的库或编写它。 vue3 事件描述
现在,如果您使用的是 Option-API(如 vue 2),您需要导入该事件文件,然后在任何组件中正确使用它。
如果您使用的是<script setup>
,则需要添加额外的步骤才能让事件库继承代码。
这是 pub-sub javascript 模式的基本示例,不要忘记添加 off 方法并在beforeUnmounted
(v3)、 beforeDestroy
(v2) 上调用它,以免每个挂载的调用都执行多个 function )
//event.js
class Event{
constructor(){
this.events = {};
}
on(eventName, fn) {
this.events[eventName] = this.events[eventName] || [];
this.events[eventName].push(fn);
}
emit = (eventName, data)=> (this.events[eventName]) ? this.events[eventName].forEach( fn => fn(data)) : '' ;
}
export default new Event();
如果你在做 vue2 之类的语法 Option-API: //in vue component
import event from './event';
//mounted or any methods
even.on('GG', data=> console.log(`GG Event received ${data}`))
//显然你必须从另一个组件发出它 //...
import event from './event';
//on mounted or methods click or...
even.emit('GG', {msg:"Vue3 is super Cool"});
如果您使用的是<script setup>
这意味着默认情况下所有变量和方法都暴露给模板。
//in main.js
import event from './event.js';
//..
app.config.globalProperties.$event = event;
//..
//note if you have an error make sure that you split the the app chaining, like this :
let app = createApp(App);
app.config.globalProperties.$event = event;
app.mount('#app');
//添加一个名为useEvent.js的文件
// useEvent.js
import { getCurrentInstance } from 'vue'
export default useEvent => getCurrentInstance().appContext.app.config.globalProperties.$event;
//在<script setup>
中使用它
import useEvent from '@/useEvent'
const event = useEvent();
event.emit('GG');
我想出了一种将事件从父组件发送到子组件的方法。 请注意,因为这是一个非常丑陋的解决方法!
//child
setup(){
// get the current instance
const instance = getCurrentInstance();
// function to find the parent instance
const getParentComponent = (name: string) => {
let component = null;
if (instance) {
let parent = instance.parent;
while (parent && !component) {
if (parent.type.name === name) {
component = parent;
}
parent = parent.parent;
}
return component;
} else {
return null;
}
};
// listener that will be called from within the parent component
const eventFunction = () => {
console.log('event fired !!')
}
onMounted(() => {
const $parent = getParentComponent('ParentComponentName');
// register the current instance to the parent component
if($parent && $parent.props && $parent.props.childInstances){
($parent.props.childInstances as any[]).push(instance)
}
})
return {
eventFunction
}
}
//parent
name: 'ParentComponentName',
props: {
childInstances: {
type: Array as PropType<any[]>,
required: false,
default: () => [] as any[]
}
},
setup(props){
const emitChildComponentEvent = (event: string) => {
if(props.childInstances.length > 0){
props.childInstances.forEach((component: any) => {
if(typeof component.proxy[event] === 'function'){
component.proxy[event]()
}
})
}
}
onMounted(() => {
emitChildComponentEvent('eventFunction');
})
}
您可以通过使用scoped slots来做到这一点。
例如,在“开槽”组件的父级中:
Parent.vue
:
<script setup lang="ts">
import { useToggle } from '@/composables'
const props = defineProps({
show: {
type: Boolean,
required: true
}
})
const { isOpen, close, open, toggle } = useToggle(props.show)
</script>
<template>
<slot
:on-open="open"
:on-close="close"
:on-toggle="toggle"
/>
</template>
*我们在其中使用了基本的切换可组合项。
在Grandparent.vue
组件中,我们可以再scope一些方法触发事件到parent的Child.vue
组件,如下:
GrandParent.vue
:
<template>
<Parent>
<template #default="{ onToggle }">
<Child
@toggle="onToggle"
/>
</template>
</Parent>
</template>
*将#default
更改为任何你的插槽名称,如果没有名称则保留为默认值。
然后在 Child.vue 组件中,我们确保向上发出事件:
Child.vue
:
<script setup lang="ts">
const emit = defineEmits<{
(e: 'toggle'): void
}>()
const toggle = () => {
emit('toggle')
}
</script>
<template>
<button @click="toggle">Toggle Event</button>
</template>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.