为何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属性,只会在组件创建时把父组件传入的doneprops值赋值给自己。后续父组件的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
相关产品推荐
相关产品推荐

