Vue 3 emit警告“Extraneous non-emits event listeners”问题解决

Vue 3 emit警告“Extraneous non-emits event listeners”问题解决

技术背景

在使用Vue 3的组合式API从子组件向父组件传递数据时,可能会遇到 [Vue warn]: Extraneous non-emits event listeners 警告。这个警告通常表示传递给组件的非 emits 事件监听器无法被自动继承,因为组件渲染的是片段或文本根节点。

实现步骤

1. 定义emits选项

在子组件中明确声明要触发的自定义事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// childcomponent.vue
<template>
<h1>{{ store.count }}</h1>
<button @click="fired">click me</button>
</template>

<script>
import useStore from "../store/store.js";
export default {
name: "HelloWorld",
emits: ["updatedcount"],
setup(_, { emit }) {
const store = useStore();

const fired = () => {
store.count++;
emit("updatedcount", store.count);
};

return {
store,
fired
};
},
};
</script>

2. 使用defineEmits(适用于<script setup>

如果使用 <script setup> 语法,使用 defineEmits 来声明自定义事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// childcomponent.vue(<script setup> 语法)
<template>
<h1>{{ store.count }}</h1>
<button @click="fired">click me</button>
</template>

<script setup>
import useStore from "../store/store.js";
const emits = defineEmits(["updatedcount"]);
const store = useStore();

const fired = () => {
store.count++;
emits("updatedcount", store.count);
};
</script>

3. 包裹模板内容

将组件的模板内容包裹在一个单一的根元素中,如 <div>

1
2
3
4
5
6
<template>
<div>
<h1>{{ store.count }}</h1>
<button @click="fired">click me</button>
</div>
</template>

核心代码

子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
<div>
<h1>{{ store.count }}</h1>
<button @click="fired">click me</button>
</div>
</template>

<script>
import useStore from "../store/store.js";
export default {
name: "HelloWorld",
emits: ["updatedcount"],
setup(_, { emit }) {
const store = useStore();

const fired = () => {
store.count++;
emit("updatedcount", store.count);
};

return {
store,
fired
};
},
};
</script>

父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<template>
<div>
{{ hello }}
<br />
<br />
<input type="text" v-model="hello.searchQuery" />
<br><br>
<button @click="hello.count--">click me too!</button>
<hello-world @updatedcount="mydata" />
</div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";
import useStore from "./store/store.js";

export default {
components: {
HelloWorld,
},
setup() {
const hello = useStore();

function mydata(event) {
console.log(event);
}

return {
hello,
mydata
};
},
};
</script>

最佳实践

  • 明确声明emits:在子组件中始终明确声明要触发的自定义事件,这样可以避免警告并提高代码的可读性。
  • 使用单一根元素:确保组件的模板有一个单一的根元素,避免渲染片段或文本根节点导致的继承问题。
  • 遵循命名规范:事件名称尽量使用小写字母,避免使用连字符或驼峰命名法带来的潜在问题。

常见问题

1. 命名问题

如果事件名称使用了连字符(kebab-case),运行时可能会抱怨没有以驼峰命名法(camelCase)声明;而使用驼峰命名法时,ESLint 可能会警告事件应该使用连字符命名。建议使用全小写字母的命名方式。

2. 包裹元素无效

有时包裹模板内容在 <div> 中可能仍然无法解决问题,这时需要检查是否正确声明了 emits 选项。


Vue 3 emit警告“Extraneous non-emits event listeners”问题解决
https://119291.xyz/posts/2025-04-14.vue3-emit-warning-solve/
作者
ww
发布于
2025年4月14日
许可协议