为什么我的 Vue 组件需要 :key?
Why does my Vue component require :key?
我有一个小的 Vue.js 组件,它显示最喜欢的星形图标。单击图标 favorites/unfavorites 元素。到目前为止,我只实现了 UI 部分,如下所示:
<template>
<div :key="favorite">
<a v-on:click="toggleFavorite" style="cursor: pointer">
<i v-show="favorite" class="text-warning fas fa-star"></i>
<i v-show="!favorite" class="text-warning far fa-star"></i>
</a>
</div>
</template>
<script>
export default {
data() {
return {
favorite: true,
}
},
mounted() {
},
methods: {
toggleFavorite() {
this.favorite = !this.favorite
}
},
props: ['team-id'],
}
</script>
<style scoped>
</style>
如您所见,逻辑非常简单。
这很好用,但让我困扰的一件事是,如果我从我的模板中删除 :key
属性,当我点击它时图标不会更新(即使我已检查基础 属性 是否 确实已正确更新)。添加 :key
使其工作,我想是因为它强制 Vue.js 在更新 favorite
时完全重新渲染组件。
为什么会这样?我对 JS 框架的世界相当陌生,所以请原谅我可能遗漏的任何明显的东西。我在网上做了一些研究,但找不到解释。我只是想确保我以正确的方式做事,而不仅仅是解决这里的问题。
好的,我认为这里的问题是您正在更改根数据对象。为了保持反应性,您不应在实例化 Vue 后更改根数据对象。
Here is your code 在一个简单的 Vue 中。我不需要 :key 来让它工作。我会保留 :key 用于内部循环。
标记
<div id="vueRoot">
<a v-on:click="toggleFavorite" style="cursor: pointer">
<i v-show="store.favorite" class="text-warning fas fa-star">Fav</i>
<i v-show="!store.favorite" class="text-warning far fa-star">Not fav</i>
</a>
</div>
代码
vm = new Vue({
el : "#vueRoot",
data() {
return { store :{
favorite: true
}}
},
mounted() {
},
methods: {
toggleFavorite() {
this.store.favorite = !this.store.favorite
}
}
}
);
这是一个改动很小的工作示例。根据您向我们展示的内容,您应该只有 元素,然后使用动态 class 列表执行您想要的操作,例如...
<i :class="['text-warning','fa-star',store.favorite?'fas':'far']"></i>
您不需要 :key,它只在 v-for 循环中才需要。我建议您将其删除并将 v-show 替换为 v-if 和 v-else 指令。
<i v-if="favorite" class="text-warning fas fa-star"></i>
<i v-else class="text-warning far fa-star"></i>
v-if 删除该部分并将其添加到 DOM 而 v-show 只是隐藏它所以这样可以很好地解决您的问题
Vue 在必要时使用虚拟 DOM 修补程序。也就是说,每当 vue 检测到 DOM 上的更改时,它都会对其进行修补以提高性能。在 DOM 中修补不会更改图标或图像。您需要替换 DOM。
因此,vue 为我们提供了每当我们需要通过替换方法更改DOM 的方式时,我们可以使用:key
绑定。
因此,:key
绑定可用于强制替换 element/component 而不是重新使用它。
以下整个 html div 将在 favorite
数据发生变化时被替换,因为我们 :key
对其进行绑定:
<div :key="favorite">
<a v-on:click="toggleFavorite" style="cursor: pointer">
<i v-show="favorite" class="text-warning fas fa-star"></i>
<i v-show="!favorite" class="text-warning far fa-star"></i>
</a>
</div>
这就是为什么 vue 强制允许我们在循环内使用 :key
绑定,因为当它检测到 data
中的变化时需要替换循环内的元素。这是从 2.2.0+
强制执行的,ESLint 也实现了此功能,因此如果您在循环中错过 :key
绑定,那么当您使用支持 eslint 的编辑器时,您将在该行看到错误,以便您可以修复错误。
只是一个意见,应该从 vue 中删除 :key
绑定的严格要求,因为我们可能想要 predefined data
的循环并且不想更改 DOM 但我们仍然使用 v-for
循环来列出更大的数据。但这种情况可能很少见。
仔细阅读documentation for :key binding,你就会有一个想法。
:key
绑定在您需要时很有用:
Properly trigger lifecycle hooks of a component
Trigger transitions
- 使用
:key
绑定替换DOM。请记住它会降低性能,因为它会替换绑定到元素的整个 DOM。
- 当您不想替换 DOM 或时,请不要使用
:key
绑定
您认为不需要 data
更改检测。这会
让 vue 在没有 :key
绑定的情况下表现更好。
这似乎是 FontAwesome CSS 的一个普遍问题,与框架无关。
在 github 上有一个问题,这里有同样的问题与 react https://github.com/FortAwesome/Font-Awesome/issues/11967
为了证明这一点,这里是同一示例的简化版本,但使用了 bootstrap 个图标
new Vue({
el: '#app',
data() {
return {
fav: true
}
}
});
<script
src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"
></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<div id="app">
<div>
<a v-on:click="fav = !fav" style="cursor: pointer">
<i v-show="fav" class="glyphicon glyphicon-star"></i>
<i v-show="!fav" class="glyphicon glyphicon-star-empty"></i>
</a>
</div>
</div>
我有一个小的 Vue.js 组件,它显示最喜欢的星形图标。单击图标 favorites/unfavorites 元素。到目前为止,我只实现了 UI 部分,如下所示:
<template>
<div :key="favorite">
<a v-on:click="toggleFavorite" style="cursor: pointer">
<i v-show="favorite" class="text-warning fas fa-star"></i>
<i v-show="!favorite" class="text-warning far fa-star"></i>
</a>
</div>
</template>
<script>
export default {
data() {
return {
favorite: true,
}
},
mounted() {
},
methods: {
toggleFavorite() {
this.favorite = !this.favorite
}
},
props: ['team-id'],
}
</script>
<style scoped>
</style>
如您所见,逻辑非常简单。
这很好用,但让我困扰的一件事是,如果我从我的模板中删除 :key
属性,当我点击它时图标不会更新(即使我已检查基础 属性 是否 确实已正确更新)。添加 :key
使其工作,我想是因为它强制 Vue.js 在更新 favorite
时完全重新渲染组件。
为什么会这样?我对 JS 框架的世界相当陌生,所以请原谅我可能遗漏的任何明显的东西。我在网上做了一些研究,但找不到解释。我只是想确保我以正确的方式做事,而不仅仅是解决这里的问题。
好的,我认为这里的问题是您正在更改根数据对象。为了保持反应性,您不应在实例化 Vue 后更改根数据对象。
Here is your code 在一个简单的 Vue 中。我不需要 :key 来让它工作。我会保留 :key 用于内部循环。
标记
<div id="vueRoot">
<a v-on:click="toggleFavorite" style="cursor: pointer">
<i v-show="store.favorite" class="text-warning fas fa-star">Fav</i>
<i v-show="!store.favorite" class="text-warning far fa-star">Not fav</i>
</a>
</div>
代码
vm = new Vue({
el : "#vueRoot",
data() {
return { store :{
favorite: true
}}
},
mounted() {
},
methods: {
toggleFavorite() {
this.store.favorite = !this.store.favorite
}
}
}
);
这是一个改动很小的工作示例。根据您向我们展示的内容,您应该只有 元素,然后使用动态 class 列表执行您想要的操作,例如...
<i :class="['text-warning','fa-star',store.favorite?'fas':'far']"></i>
您不需要 :key,它只在 v-for 循环中才需要。我建议您将其删除并将 v-show 替换为 v-if 和 v-else 指令。
<i v-if="favorite" class="text-warning fas fa-star"></i>
<i v-else class="text-warning far fa-star"></i>
v-if 删除该部分并将其添加到 DOM 而 v-show 只是隐藏它所以这样可以很好地解决您的问题
Vue 在必要时使用虚拟 DOM 修补程序。也就是说,每当 vue 检测到 DOM 上的更改时,它都会对其进行修补以提高性能。在 DOM 中修补不会更改图标或图像。您需要替换 DOM。
因此,vue 为我们提供了每当我们需要通过替换方法更改DOM 的方式时,我们可以使用:key
绑定。
因此,:key
绑定可用于强制替换 element/component 而不是重新使用它。
以下整个 html div 将在 favorite
数据发生变化时被替换,因为我们 :key
对其进行绑定:
<div :key="favorite">
<a v-on:click="toggleFavorite" style="cursor: pointer">
<i v-show="favorite" class="text-warning fas fa-star"></i>
<i v-show="!favorite" class="text-warning far fa-star"></i>
</a>
</div>
这就是为什么 vue 强制允许我们在循环内使用 :key
绑定,因为当它检测到 data
中的变化时需要替换循环内的元素。这是从 2.2.0+
强制执行的,ESLint 也实现了此功能,因此如果您在循环中错过 :key
绑定,那么当您使用支持 eslint 的编辑器时,您将在该行看到错误,以便您可以修复错误。
只是一个意见,应该从 vue 中删除 :key
绑定的严格要求,因为我们可能想要 predefined data
的循环并且不想更改 DOM 但我们仍然使用 v-for
循环来列出更大的数据。但这种情况可能很少见。
仔细阅读documentation for :key binding,你就会有一个想法。
:key
绑定在您需要时很有用:
Properly trigger lifecycle hooks of a component
Trigger transitions
- 使用
:key
绑定替换DOM。请记住它会降低性能,因为它会替换绑定到元素的整个 DOM。 - 当您不想替换 DOM 或时,请不要使用
:key
绑定 您认为不需要data
更改检测。这会 让 vue 在没有:key
绑定的情况下表现更好。
这似乎是 FontAwesome CSS 的一个普遍问题,与框架无关。 在 github 上有一个问题,这里有同样的问题与 react https://github.com/FortAwesome/Font-Awesome/issues/11967
为了证明这一点,这里是同一示例的简化版本,但使用了 bootstrap 个图标
new Vue({
el: '#app',
data() {
return {
fav: true
}
}
});
<script
src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"
></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<div id="app">
<div>
<a v-on:click="fav = !fav" style="cursor: pointer">
<i v-show="fav" class="glyphicon glyphicon-star"></i>
<i v-show="!fav" class="glyphicon glyphicon-star-empty"></i>
</a>
</div>
</div>