Vue Todo应用:点击添加按钮后无法清空输入框description问题求助
问题分析与解决方案
问题根源
你当前的代码存在两个核心问题:
- 复用了同一个
reactive对象todoTemplate传递给manager.addTodo,导致管理器中存储的是该对象的引用——后续修改todoTemplate.description会同时影响已添加到列表中的待办项,且输入框的清空操作可能因引用共享出现异常。 todoTemplate的id和timeStamp在初始化时就固定,多次添加会生成重复ID,引发Vue列表渲染的key冲突问题。
解决方案
推荐使用单独的ref变量管理输入框内容,每次添加待办时创建全新的对象实例,避免引用共享问题。修改后的完整代码如下:
<script setup> import { TodoManager } from "../../../lib/TodoManger"; import { computed, ref } from "vue"; import List from "./List.vue"; import Todo from "../Todo.vue"; // 仅作为待办项结构模板,无需响应式 const todoTemplate = { is_success: false } const manager = ref(new TodoManager()); const addTodo = ref(false); // 用ref单独管理输入框值,清空操作更直观可靠 const newTodoDesc = ref(""); const todos = computed(() => { return manager.value.getNotDone(); }); const todos_success = computed(() => { return manager.value.getDone(); }); function handleDelete(id) { manager.value.deleteTodo(id); } function handleState(id) { manager.value.updateTodoState(id); } function addTodohandle() { // 过滤空内容 if (!newTodoDesc.value.trim()) return; // 创建独立的待办项对象,生成唯一ID和时间戳 const newTodo = { ...todoTemplate, id: Date.now(), description: newTodoDesc.value, timeStamp: Date.now() }; manager.value.addTodo(newTodo); newTodoDesc.value = ""; // 清空输入框 addTodo.value = false; // 关闭弹窗 } </script> <template> <div class="p-3"> <button class="btn bg-slate-200" @click="addTodo = !addTodo">New Todo</button> </div> <div class="absolute flex w-full h-1/2 items-center justify-center" v-show="addTodo"> <div class="w-1/6 h-1/2 rounded-md bg-slate-500 border border-cyan-700 flex justify-center items-center flex-col gap-3"> <input type="text" class="w-1/2 h-1/6 rounded-sm input max-w-xs" placeholder="New Todo" v-model="newTodoDesc" /> <div class="flex gap-3 pt-5"> <button class="btn bg-blue-900" @click="addTodohandle">Add Todo</button> <button class="btn bg-red-700" @click="addTodo = !addTodo; newTodoDesc = ''">Cancel</button> </div> </div> </div> <List> <Todo v-for="todo in todos" :key="todo.id" :description="todo.description" :isSuccess="todo.is_success" :id="todo.id" :todo="todo" @delete-todo="handleDelete" @edit-todo="editTodo" @check-todo="handleState" /> <template #success> <Todo v-for="todo in todos_success" :key="todo.id" :description="todo.description" :isSuccess="todo.is_success" :id="todo.id" :todo="todo" @delete-todo="handleDelete" @edit-todo="editTodo" @check-todo="handleState" /> </template> </List> </template> <style> </style>
关键修改点
- 移除了
todoTemplate的reactive包装,仅作为结构模板使用。 - 新增
newTodoDescref变量绑定输入框,清空操作直接修改该变量即可。 addTodohandle中创建独立的待办项对象,确保每个待办都是独立实例,同时生成唯一ID避免渲染冲突。- 取消按钮添加了清空输入框的逻辑,提升用户体验。
备选方案(保留原reactive模板)
如果希望继续使用reactive的todoTemplate,可以通过克隆对象避免引用传递:
function addTodohandle() { if (!todoTemplate.description.trim()) return; // 克隆reactive对象,生成新实例 const newTodo = structuredClone(todoTemplate); newTodo.id = Date.now(); newTodo.timeStamp = Date.now(); manager.value.addTodo(newTodo); todoTemplate.description = ""; addTodo.value = false; }
内容的提问来源于stack exchange,提问作者anina
相关产品推荐
相关产品推荐

