Vue3 – 警告组件触发了事件,但它既未在emits选项中声明,也未作为prop。

huangapple go评论45阅读模式
英文:

Vue3 - Warning Component emitted event but it is neither declared in the emits option nor as an prop

问题

你的代码中似乎存在一个问题,Vue 3的emits选项需要在组件中声明事件,但你的组件中似乎没有声明update:modelValue事件。这就是为什么你会收到警告消息的原因。

为了解决这个问题,你可以在你的组件中声明emits选项并包含update:modelValue事件,如下所示:

emits: ['update:modelValue', 'onOutsideClicked'],

这将告诉Vue你的组件会触发update:modelValue事件,从而消除警告。

不过,请确保你的组件确实需要使用modelValue来传递数据,因为这通常是用于支持v-model的一个约定,如果你的组件不需要这个功能,你可以考虑不使用modelValue来传递数据,从而避免这个警告。

英文:

I'm trying to remove some warnings for my project, which is in vue3 using vuetify3.

Currenlty I've a component that is a side dialog

<template>
	<div>
		<slot name="activator" :show="() => setShowDialog(true)" :close="() => setShowDialog(false)" />
		<VDialog
			v-model="componentData.showDialog"
			@click:outside="onClickOutside"
			:width="componentProperties.width"
			:min-width="componentProperties.minWidth"
			:max-width="componentProperties.maxWidth"
			:content-class="contentClass"
			persistent
			transition="slide-x-reverse-transition"
		>
			<VCard v-show="componentData.showDialog" v-fill-parent>
				<VCardTitle v-if="hasTitle" :class="componentProperties.titleClass">
					<VRow justify="center" align="center">
						<slot name="title">
							<span v-if="componentProperties.title">{{ componentProperties.title }}</span>
						</slot>
						<VSpacer />
						<VCol v-if="componentProperties.showTopCloseButton" cols="1">
							<VBtn
								@click.stop.prevent="() => setShowDialog(false)"
								color="transparent"
								elevation="0"
								size="medium"
							>
								<IconifyMdiClose />
							</VBtn>
						</VCol>
					</VRow>
				</VCardTitle>

				<slot name="body">
					<VCardText>
						<slot name="content-prepend" />
						<slot>
							<slot name="content" />
						</slot>
						<slot name="content-append" />
					</VCardText>
				</slot>
				<VCardActions>
					<slot name="actions" :show="() => setShowDialog(true)" :close="() => setShowDialog(false)" />
				</VCardActions>
			</VCard>
		</VDialog>
	</div>
</template>

<script setup lang="ts">
import { Events } from '@enums/events';
export interface IDialogConfirmComponentProperties {
	modelValue?: boolean;
	modelData?: any;
	title?: string;
	isActive?: boolean;
	showTopCloseButton?: boolean;
	titleClass?: string;
	fillHeight?: boolean;
	persistent?: boolean;
	minWidth?: string | number;
	maxWidth?: string | number;
	width?: string | number;
}

export interface IDialogConfirmComponentEvents {
	(e: 'onOutsideClicked'): void;
	(e: 'update:isActive', val?: boolean): void;
	(e: 'update:modelValue', visible?: boolean): void;
}

export interface IDialogConfirmComponentData {
	showDialog?: boolean;
}

const componentProperties = withDefaults(defineProps<IDialogConfirmComponentProperties>(), {
	persistent: false,
	fillHeight: true,
	modelValue: false,
	isActive: true,
	showTopCloseButton: false,
	titleClass: 'pt-5 text-wrap',
	width: 'auto',
	minWidth: 650,
	maxWidth: 650,
});
const componentData = reactive<IDialogConfirmComponentData>({
	showDialog: false,
});
const emits = defineEmits<IDialogConfirmComponentEvents>();
const slots = useSlots();
const hasTitle = computed(() => !!slots['title'] || !!componentProperties?.title);
const contentClass = computed(() => {
	return ['side-dialog', componentProperties.fillHeight ? 'fill-height' : ''].join(' ');
});

function onClickOutside(payload: MouseEvent) {
	emits('onOutsideClicked');
	if (componentProperties.persistent) return;
	setShowDialog(false);
}

watch(
	() => componentData.showDialog,
	showDialog => {
		componentData.showDialog = showDialog;
		emitsDialogVisibleChanges();
	},
);
watch(
	() => componentProperties.modelValue,
	showDialog => {
		componentData.showDialog = showDialog;
	},
);
function setShowDialog(value: boolean) {
	componentData.showDialog = value;
}
function emitsDialogVisibleChanges() {
	if (componentProperties.modelValue === undefined || componentProperties.modelValue === null) return;
	emits('update:isActive', componentData.showDialog);
	emits('update:modelValue', componentData.showDialog);
}
</script>
<style lang="css">
.side-dialog {
	inset-block-start: 0 !important;
	inset-inline-end: 0 !important;
}
</style>

Which then I called like:

<template>
	<SideDialog title="Configurations" show-top-close-button v-model="isDialogVisible">
		<template #activator="{ show }">
			<VBtn :variant="componentProperties.variant" @click.stop.prevent="show">
				<VIcon>mdi-cog</VIcon>
			</VBtn>
		</template>
		<VRow justify="center" align="center">
			<span>teste</span>
		</VRow>
	</SideDialog>
</template>
<script setup lang="ts">
import type { ButtonVariant } from '@/types/vuetify';
export interface IConfigurationComponentProperties {
	variant?: ButtonVariant;
}
const componentProperties = withDefaults(defineProps<IConfigurationComponentProperties>(), {
	variant: 'plain',
});
const isDialogVisible = ref(false);
</script>

But I'm currently it's always consoling a warning saying:

> component emitted event "update:modelValue" but it is neither declared in the emits option nor as an "onUpdate:modelValue" prop.

Am I missing something trivial here? I mean I'm listening to the modelValue update event.

Why is it complaining about it?

答案1

得分: 1

这个答案Vue 3发出警告:“非emit事件侦听器过多”可能对你有帮助。

将模板包装在一个<div>中可以解决这个警告。

<template>
<div>
<slot
...
</VDialog>
</div>
</template>

请检查你的发射是否仍然按预期工作。

Sandbox

英文:

This answer to vue 3 emit warning " Extraneous non-emits event listeners" could help you.

Wrapping the template in a <div> fixes the warning.

<template>
<div>
<slot
...
</VDialog>
</div>
</template>

Please check if your emits still works as intended.

Sandbox

huangapple
  • 本文由 发表于 2023年4月17日 07:04:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76030736.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定