You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue为何复用元素?如何避免复用导致的HTML元素状态残留

Vue列表更新时元素复用导致自定义属性残留的问题

我在Vue项目开发中遇到一个异常行为:更新JavaScript数组后,新的列表项会复用旧的HTML元素,导致旧元素上的自定义属性被新项继承,出现不符合预期的状态。

示例代码

HTML部分

<head>
    <title>Test</title>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@3" defer></script>
    <script src="script.js" defer></script>
    <style>
        div[time-isselected="true"] {
            background: rgb(0, 255, 0);
        }
    </style>
</head>
<body>
    <div class="day container">
        <div class="selection" v-for="day in daysList">
            <input type="radio" class="radio-day" name="radio" 
            :id="returnTheInput(day)" :value="returnTheInput(day)" @click="setSelectedDay(day)">
            <label :for="returnTheInput(day)">{{day}}</label>
        </div>
    </div>

    <div class="hour-container">
        <div v-for="hour in hoursList" class="hour" :id="returnTheInput(hour)" @click="setSelectedHour(hour)">
            {{hour}}
        </div>
    </div>
</body>

JavaScript部分

let daysList = ["mon 15","tue 16"];
let hoursList = [];
let selectedDay = undefined;

const valuesForTest = {
    [daysList[0]]: ["10:00", "11:00"],
    [daysList[1]]: ["15:00", "16:00"]
}

const { createApp } = Vue;

const vm = Vue.createApp({
    data(){
        return {
            daysList: daysList,
            hoursList: hoursList
        };
    },
    methods: {
        returnTheInput(input){
            return input;
        },
        setSelectedDay(day){
            selectedDay = day;
            vm.hoursList.splice(0, hoursList.length); //Vue is reactive to splice
            for(let i = 0; i < valuesForTest[selectedDay].length; i++){
                vm.hoursList.push(valuesForTest[selectedDay][i]);
            }
        },
        setSelectedHour(hour){
            document.getElementById(hour).setAttribute("time-isselected", "true");
        }
    }
}).mount("body");

复现步骤

  • 选择某一天
  • 选择一个小时(点击它)
  • 选择另一天

执行上述操作后,新切换的小时项会显示为选中状态,这并非预期结果。原本以为新项会对应全新的HTML元素,但实际上Vue在复用旧元素。

解决方法

方法1:给v-for添加唯一key属性

Vue的v-for默认会复用元素提升性能,它基于元素顺序而非内容判断是否复用。给v-for绑定唯一key可以让Vue识别每个项的唯一性,从而避免复用旧元素:

修改小时列表的v-for代码:

<div v-for="hour in hoursList" :key="hour" class="hour" :id="returnTheInput(hour)" @click="setSelectedHour(hour)">
    {{hour}}
</div>

这里用hour作为key(每个小时值唯一),添加后Vue会在列表更新时销毁旧元素并创建新元素,旧元素的自定义属性就不会被继承。

方法2:用Vue响应式状态管理选中状态(更推荐)

直接操作DOM设置属性不符合Vue响应式理念,更好的做法是将选中状态存入响应式数据,通过数据驱动视图:

  1. 在data中添加选中状态:
data(){
    return {
        daysList: daysList,
        hoursList: hoursList,
        selectedHour: null
    };
}
  1. 修改setSelectedHour方法,更新响应式状态而非直接操作DOM:
setSelectedHour(hour){
    this.selectedHour = hour;
}
  1. 修改小时元素模板,通过状态绑定属性:
<div v-for="hour in hoursList" :key="hour" class="hour" :id="returnTheInput(hour)" 
    @click="setSelectedHour(hour)" :time-isselected="selectedHour === hour">
    {{hour}}
</div>

切换日期时,selectedHour不会自动关联新的小时项,视图会根据状态自动更新,完全避免DOM操作带来的问题。


内容的提问来源于stack exchange,提问作者Francesco Urdih

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 14:29:09