现在我需要从父组件向子组件发出事件。 我看到在Vue版本3中,$on
、$off
和$once
实例方法被删除了。 应用程序实例不再实现事件发射器接口。
那么我现在如何在Vue版本3中从父组件发出事件并在子组件中监听呢?
现在我需要从父组件向子组件发出事件。 我看到在Vue版本3中,$on
、$off
和$once
实例方法被删除了。 应用程序实例不再实现事件发射器接口。
那么我现在如何在Vue版本3中从父组件发出事件并在子组件中监听呢?
<!-- 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();
return { childComponentRef }
}
}
</script>
<!-- Child -->
<script>
export default {
setup() {
const expandAll= () => {
//logic...
}
return { expandAll}
}
}
</script>
在父子组件之间,不应该从子组件监听父组件的事件,而是应该向子组件传递一个prop,如果子组件需要更新数据,则应该从子组件向父组件发出事件以更新状态。
只读生命周期: 父组件 > Prop > 子组件
读/写生命周期: 父组件 > Prop > 子组件 > 发送事件 > 父组件 > 更新 > 子组件更新
ctrl
+v
呢?当页面上有上传组件 时,我想将剪贴板的内容传送出去。 - Dennis de Laat您可以使用作用域插槽来实现这一点。
例如,在父组件中使用“插槽”:
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
组件中,我们可以将一些方法触发事件限定于父级的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>
我想到了一种从父组件向子组件发出事件的方法。请注意,这是一种非常丑陋的解决方法!!
//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');
})
}
如果你像我一样,在Vue2中从任何父/子到任何子/父上调用一些事件时,使用this.$root.$on(...)
和this.$root.$emit(...)
来保持代码更加清晰,而不是分别使用大量的emits和props并使代码爆炸..
从Vue3文档中,事件总线模式可以通过使用实现事件发射器接口的外部库来替换。使用实现pub-sub模式的库或编写它。 vue3 event description
现在,如果您正在使用Option-API(例如vue 2),则需要导入该事件文件,然后在任何组件中立即使用它。
如果您使用的是<script setup>
,则需要添加额外的步骤才能使用该事件库,这是代码。
这是发布-订阅JavaScript模式的基本示例,请不要忘记添加off方法并在beforeUnmounted
(v3),beforeDestroy
(v2)上调用它,以避免为每个已安装的调用执行多个函数)。
//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语法: //在Vue组件中
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');