Vue 3 passing array warning: Extraneous non-props attributes were passed to component but could not be automatically inherited

Vue 3 passing array warning: Extraneous non-props attributes were passed to component but could not be automatically inherited

技术背景

在Vue 3开发中,当我们向组件传递属性时,可能会遇到 Extraneous non-props attributes 警告。这个警告表明传递给组件的非props属性无法自动继承,因为组件渲染的是片段或文本根节点。此问题通常在组件没有单一根元素时出现,了解如何解决该警告对于保证项目代码的健壮性和可读性非常重要。

实现步骤

问题复现

在示例中,父组件 views/Home.vue 向子组件 components/ItemProperties.vue 传递数组,同时传递了 class 属性:

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
<!-- views/Home.vue -->
<template>
<div class="wrapper">
<section v-for="(item, index) in items" :key="index" class="box">
<ItemProperties class="infobox-item-properties" :info="item.properties" />
</section>
</div>
</template>
<script>
import { ref } from 'vue'
import { data } from '@/data.js'
import ItemProperties from '@/components/ItemProperties.vue'

export default {
components: {
ItemProperties
},
setup() {
const items = ref(data)

return {
items
}
}
}
</script>

子组件 ItemProperties.vue 渲染多个 <div> 元素,没有单一根元素:

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
<!-- components/ItemProperties.vue -->
<template>
<div class="infobox-item-property" v-for="(object, index) in info" :key="index">
<span class="infobox-item-title">{{ object.name }}:</span>
<span v-if="object.type === 'rating'">
<span v-for="(v, k) in object.value" :key="k">{{ object.icon }}</span>
</span>
<span v-else>
<span>{{ object.value }}</span>
</span>
</div>
</template>

<script>
export default {
props: {
info: {
type: Array,
required: false,
default: () => [
{
name: '',
value: '',
type: 'string',
icon: ''
}
]
}
}
}
</script>

解决方法

方法一:移除多余属性或添加根元素

移除 class="infobox-item-properties",或者在子组件中添加一个根元素来包裹内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- components/ItemProperties.vue -->
<template>
<div>
<div class="infobox-item-property" v-for="(object, index) in info" :key="index">
<span class="infobox-item-title">{{ object.name }}:</span>
<span v-if="object.type === 'rating'">
<span v-for="(v, k) in object.value" :key="k">{{ object.icon }}</span>
</span>
<span v-else>
<span>{{ object.value }}</span>
</span>
</div>
</div>
</template>

方法二:禁用属性继承

在子组件中设置 inheritAttrs: false 来禁用属性的自动继承:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default {
name: "ItemProperties",
inheritAttrs: false,
props: {
info: {
type: Array,
required: false,
default: () => [
{
name: '',
value: '',
type: 'string',
icon: ''
}
]
}
}
}

在Vue 3.3+ 版本中,还可以使用 <script setup> 语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script setup>
defineOptions({ inheritAttrs: false })
</script>

<template>
<div>
<div class="infobox-item-property" v-for="(object, index) in info" :key="index">
<span class="infobox-item-title">{{ object.name }}:</span>
<span v-if="object.type === 'rating'">
<span v-for="(v, k) in object.value" :key="k">{{ object.icon }}</span>
</span>
<span v-else>
<span>{{ object.value }}</span>
</span>
</div>
</div>
</template>

方法三:声明属性

在子组件的 props 中声明传递的属性,例如声明 class 属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default {
props: ["class"],
props: {
info: {
type: Array,
required: false,
default: () => [
{
name: '',
value: '',
type: 'string',
icon: ''
}
]
}
}
}

核心代码

以下是添加根元素解决问题的完整代码示例:

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<!-- views/Home.vue -->
<template>
<div class="wrapper">
<section v-for="(item, index) in items" :key="index" class="box">
<ItemProperties class="infobox-item-properties" :info="item.properties" />
</section>
</div>
</template>
<script>
import { ref } from 'vue'
import { data } from '@/data.js'
import ItemProperties from '@/components/ItemProperties.vue'

export default {
components: {
ItemProperties
},
setup() {
const items = ref(data)

return {
items
}
}
}
</script>

<!-- components/ItemProperties.vue -->
<template>
<div>
<div class="infobox-item-property" v-for="(object, index) in info" :key="index">
<span class="infobox-item-title">{{ object.name }}:</span>
<span v-if="object.type === 'rating'">
<span v-for="(v, k) in object.value" :key="k">{{ object.icon }}</span>
</span>
<span v-else>
<span>{{ object.value }}</span>
</span>
</div>
</div>
</template>

<script>
export default {
props: {
info: {
type: Array,
required: false,
default: () => [
{
name: '',
value: '',
type: 'string',
icon: ''
}
]
}
}
}
</script>

最佳实践

  • 在设计组件时,尽量保证组件有单一根元素,避免渲染片段。
  • 对于需要传递属性的情况,明确声明 props,避免不必要的属性传递。
  • 合理使用 inheritAttrs 来控制属性的继承行为。

常见问题

为什么在Vue 2中没有这个问题?

在Vue 2中,组件必须渲染单一根元素,所以不会出现因多个根元素导致的属性无法继承问题。而Vue 3允许渲染多个根元素(片段),因此可能会触发此警告。

除了上述方法,还有其他解决办法吗?

还可以使用 v-bind="$attrs" 来手动处理属性传递,或者动态添加类名,如 myComponentEl.classList.add('awesome-class')。同时,对于Vue 3.3+ 版本,也可以使用 defineProps 来解决警告:

1
const props = defineProps(['class'])

Vue 3 passing array warning: Extraneous non-props attributes were passed to component but could not be automatically inherited
https://119291.xyz/posts/vue3-passing-array-warning-handling/
作者
ww
发布于
2025年4月14日
许可协议