每当我修改用于渲染v-for列表的数组时,我都会遇到此问题。
我们说我有三个项目的v-for列表:
<ul>
<li v-for="item in items"></li>
<ul></ul>
<ul>
<li>One</li> <!-- Has focus or a specific child component -->
<li>Two</li>
<li>Three</li>
</ul>
向items数组添加一个新项目:
<ul>
<li>New Item</li> <!-- Focuses on this item, the child component seems to be moved here -->
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
焦点似乎在移动......
请查看说明问题https://jsfiddle.net/gu9wyctr/
的小提琴我知道这种行为必须有充分的理由,但我需要对其进行管理或完全避免。想法?
修改
我刚刚意识到我的解释很模糊。这里有一个更新的小提示来说明问题https://jsfiddle.net/keligijus/d1s4mjj7/
问题是输入文本被移动到另一个元素......
我的现实生活中的榜样。我有一个类似论坛的帖子列表。每个帖子都有一个回复输入。如果有人在其他用户输入回复时发布新帖子,则该用户输入的输入将被移动到另一个帖子。就像小提琴中的例子一样。
答案 0 :(得分:4)
提供密钥就是答案!
https://vuejs.org/v2/guide/list.html#key
当Vue更新使用v-for渲染的元素列表时,它默认使用“就地补丁”策略。如果数据项的顺序已经改变,而不是移动DOM元素以匹配项的顺序,Vue将简单地就地修补每个元素并确保它反映应该在该特定索引处呈现的内容。这类似于track-by =&#34; $ index&#34;在Vue 1.x。
此默认模式是有效的,但仅在列表呈现输出不依赖于子组件状态或临时DOM状态(例如表单输入值)时才适用。
为Vue提供一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有元素,您需要为每个项目提供唯一的键属性。 key的理想值是每个项目的唯一ID。这个特殊属性大致等同于1.x中的track-by,但它的作用类似于属性,因此您需要使用v-bind将其绑定到动态值(在此处使用速记):
<li v-for="(item, index) in items" :key="'item-'+item">
<input :id="'item-'+index" type="text" style="width:80%;">
</li>
更新了小提示,表明这有效https://jsfiddle.net/keligijus/d1s4mjj7/3/
答案 1 :(得分:0)
试试这个:
var app = new Vue({
el: '#app',
data: {
messages: [
{ message: 'Hello Vue!', id: 0 },
{ message: 'Hello Vuex!', id: 1 },
{ message: 'Hello VueRouter!', id: 2 }
],
msg: null,
focus: 'item-1'
},
mounted () {
document.getElementById(this.focus).focus()
setTimeout(() => {
this.messages.unshift({ message: 'Focus moves!', id: 3 })
}, 2000)
setTimeout(() => {
this.messages.unshift({ message: 'Moves again...', id: 4 })
this.msg = `I suppose this happens because of the way DOM is updated and I understand there must a good reason for this. However I need to avoid this behaviour. How can I do this?`
}, 4000)
},
updated: function () {
document.getElementById(this.focus).focus()
}
})
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<ul>
<li v-for="(message, index) in messages">
<input :id="'item-'+message.id" type="text" v-model="message.message" style="width:80%;">
</li>
<li v-if="msg">{{msg}}</li>
</ul>
</div>
&#13;
基本上即使添加了新项目,我也会使id相同,然后我可以跟踪焦点项目,并在更新后再次关注它们。