Vue 列表渲染默认复用 DOM 导致的问题

举报
林欣 发表于 2025/12/08 17:43:56 2025/12/08
【摘要】 ❌ 问题场景:表单输入错乱假设我们有一个列表,渲染两个输入框,用户可以在输入框中输入内容:<template> <div> <button @click="swapItems">交换列表顺序</button> <div v-for="(item, index) in list" :key="index"> <input :placeholder="item.plac...

问题场景:表单输入错乱

假设我们有一个列表,渲染两个输入框,用户可以在输入框中输入内容:

<template>
  <div>
    <button @click="swapItems">交换列表顺序</button>
    <div v-for="(item, index) in list" :key="index">
      <input :placeholder="item.placeholder">
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: [
        { id: 1, placeholder: "请输入姓名" },
        { id: 2, placeholder: "请输入年龄" }
      ]
    };
  },
  methods: {
    swapItems() {
      // 交换列表中两项的顺序
      this.list.reverse();
    }
  }
};
</script>

操作步骤

  1. 用户在第一个输入框(“请输入姓名”)输入 "张三",在第二个输入框(“请输入年龄”)输入 "25"
  2. 点击“交换列表顺序”按钮,list 数组顺序被反转。
  3. Vue 默认会复用 DOM 元素(因为 key 用了 index,而索引 01 只是交换了位置)。

问题表现

  • 用户输入的内容 会跟着 DOM 元素移动,导致:
    • 原本输入 "张三" 的输入框(第一个)现在变成了 "25"(因为复用了第二个 <input>)。
    • 原本输入 "25" 的输入框现在变成了 "张三"
  • 用户看到的输入内容突然交换了,但实际数据(list)并没有变,只是 DOM 被复用了。

🔍 原因分析

Vue 默认通过 key 来判断是否复用 DOM 元素:

  1. 如果 keyindex(如 :key="index"),交换数组顺序后,索引 01 只是换了位置,Vue 会认为这两个 <input> 可以直接复用,只是移动了位置。
  2. <input> 的当前值(用户输入的内容)是 DOM 的临时状态,Vue 不会自动帮你保存或同步它!
  3. 结果就是:输入框的值跟着 DOM 元素移动,导致错乱。

正确做法:唯一 key + 数据驱动

方法 1:用唯一 id 作为 key,并避免依赖 DOM 状态

<template>
  <div>
    <button @click="swapItems">交换列表顺序</button>
    <div v-for="item in list" :key="item.id">
      <!-- 用 item.id 作为 key,且输入值绑定到数据 -->
      <input :placeholder="item.placeholder" v-model="item.value">
    </div>
    <p>当前数据:{{ list }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: [
        { id: 1, placeholder: "请输入姓名", value: "" },
        { id: 2, placeholder: "请输入年龄", value: "" }
      ]
    };
  },
  methods: {
    swapItems() {
      this.list.reverse(); // 交换顺序
    }
  }
};
</script>

关键改进

  1. key 使用唯一标识(item.id
    • Vue 能准确知道每个列表项的身份,不会错误复用 DOM。
  2. 输入值绑定到数据(v-model
    • 用户输入的内容会实时同步到 listvalue 字段,而不是依赖 DOM 的临时状态。
  3. 交换顺序后
    • Vue 会根据 key 重新匹配 DOM 元素,但输入值已经保存在数据中,不会错乱。

📌 总结

问题场景(错误) 正确做法
index 作为 key 用唯一 id 作为 key
依赖 DOM 临时状态(如 <input> 的当前值) v-model 绑定到数据
交换顺序后输入框内容错乱 数据和 DOM 正确同步,无错乱

核心原则

  • Vue 的默认复用策略要求列表渲染结果不依赖 DOM 的临时状态
  • 如果列表项有交互(如表单输入),必须用 v-model 绑定数据,并用唯一 key 确保正确复用。

这样就能避免“输入内容突然跑到其他输入框”的诡异问题了!

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。