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

Vue Todo应用:点击添加按钮后无法清空输入框description问题求助

问题分析与解决方案

问题根源

你当前的代码存在两个核心问题:

  1. 复用了同一个reactive对象todoTemplate传递给manager.addTodo,导致管理器中存储的是该对象的引用——后续修改todoTemplate.description会同时影响已添加到列表中的待办项,且输入框的清空操作可能因引用共享出现异常。
  2. 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包装,仅作为结构模板使用。
  • 新增newTodoDesc ref变量绑定输入框,清空操作直接修改该变量即可。
  • 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 17:18:11