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

为何Vue计算属性可维持响应式,data属性却无法解决复选框状态bug?

Vue复选框状态丢失问题解答

问题描述

我正在学习MDN的Vue条件渲染教程,其中提到复选框勾选状态在编辑取消后丢失的小bug可通过计算属性解决。现咨询:即使ToDoItem.vue的data中的isDone已随勾选变为true,为何点击编辑再取消后复选框仍处于未勾选状态?计算属性为何能修复该bug?

相关代码片段

ToDoItem.vue

<template>
  <div class="stack-small" v-if="!isEditing">
    <div class="custom-checkbox">
      <input
        type="checkbox"
        class="checkbox"
        :id="id"
        :checked="isDone"
        @change="$emit('checkbox-changed')"
      />
      <label :for="id" class="checkbox-label">{{ label }}</label>
    </div>
    <div class="btn-group">
      <button
        type="button"
        class="btn"
        ref="editButton"
        @click="toggleToItemEditForm"
      >
        Edit <span class="visually-hidden">{{ label }}</span>
      </button>
      <button type="button" class="btn btn__danger" @click="deleteToDo">
        Delete <span class="visually-hidden">{{ label }}</span>
      </button>
    </div>
  </div>
  <to-do-item-edit-form
    v-else
    :id="id"
    :label="label"
    @item-edited="itemEdited"
    @edit-cancelled="editCancelled"
  ></to-do-item-edit-form>
</template>

<script>
import ToDoItemEditForm from "./ToDoItemEditForm";

export default {
  components: {
    ToDoItemEditForm,
  },

  props: {
    label: { required: true, type: String },
    done: { default: false, type: Boolean },
    id: { required: true, type: String },
  },

  data() {
    return {
      isEditing: false,
      isDone: this.done, // 删除该行并使用下方computed可解决bug
    };
  },
  
  // computed: {
  //   isDone() {
  //     return this.done;
  //   },
  // },
};
</script>

App.vue

<template>
  <div id="app">
    <h1>To-Do List</h1>
    <to-do-form @todo-added="addToDo"></to-do-form>
    <h2 id="list-summary" ref="listSummary" tabindex="-1"> {{ listSummary }} </h2>
    <ul aria-labelledby="list-summary" class="stack-large">
      <li v-for="item in ToDoItems" :key="item.id">
        <to-do-item
          :label="item.label"
          :done="item.done"
          :id="item.id"
          @checkbox-changed="updateDoneStatus(item.id)"
          @item-deleted="deleteToDo(item.id)"
          @item-edited="editToDo(item.id, $event)"
        >
        </to-do-item>
      </li>
    </ul>
  </div>
</template>

<script>
import ToDoItem from "./components/ToDoItem.vue";
import ToDoForm from "./components/ToDoForm.vue";
import uniqueId from "lodash.uniqueid";

export default {
    name: "app",
    components: {
    ToDoItem,
    ToDoForm,
    },

  data() {
    return {
      ToDoItems: [],
    };
  },

methods: {
  updateDoneStatus(toDoId) {
    const toDoToUpdate = this.ToDoItems.find((item) => item.id === toDoId);
    toDoToUpdate.done = !toDoToUpdate.done;
    console.dir(toDoToUpdate.done)
  },
};
</script>

问题原因

  • data属性仅初始化一次:ToDoItem组件里的isDone是data属性,只会在组件创建时把父组件传入的done props值赋值给自己。后续父组件的done更新时,这个data属性不会自动同步,始终保持初始化时的旧值。
  • 勾选后的状态未同步到子组件data:当你勾选复选框,父组件App.vue的ToDoItems数组中对应项的done确实会被修改,但子组件的data.isDone并没有跟着更新,它还是原来的数值。
  • v-if触发DOM重建:点击编辑时,isEditing变为true,v-if="!isEditing"会销毁复选框的DOM;取消编辑时,isEditing变回false,复选框DOM会重新创建,此时data.isDone还是旧值,所以复选框显示未勾选。

计算属性修复的原理

计算属性是响应式依赖追踪的:定义的isDone计算属性直接返回this.done(父组件传入的props),当父组件的done状态更新时,计算属性会自动重新计算并返回最新值。

  • 取消编辑重新渲染复选框时,计算属性会读取父组件最新的done状态,因此复选框能正确显示勾选状态。
  • 计算属性会自动追踪依赖的变化,只要props.done改变,它就会同步更新,完全不需要手动维护状态同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 10:50:36