Svelte中Todo项编辑按钮失效问题排查及修复请求
问题:Svelte中Todo项Edit按钮分离函数后失效的原因及修复方案
在以下Svelte代码中,单个Todo项的Edit按钮绑定到独立的editTodo函数后无法正常工作,该函数本应将isEdited属性设为true。但将逻辑内联写在on:click(如<button on:click={() => isEdited = true}>)时却能正常运行,这是为什么?如何修改代码让分离的函数生效?
失效原因
这是JavaScript基本类型的值传递特性导致的:isEdited是布尔值(属于基本类型),当你把它作为参数传给editTodo时,传递的是值的副本,而非原Todo对象的属性引用。函数内执行isEdited = true只是修改了这个副本,完全不会影响原Todo对象里的isEdited属性,因此无法触发Svelte的响应式更新。
而内联写法中,isEdited = true直接操作的是原Todo对象的属性(#each解构时的isEdited是原对象属性的绑定引用),所以能正确修改并触发视图更新。
修复方案
要修改原Todo对象的属性,需将整个Todo对象作为参数传入editTodo函数,利用对象的引用类型特性,直接修改对象的isEdited属性,这样就能触发Svelte的响应式更新。
修改后的完整代码:
<script> let todos = [ { desc: 'Get some groceries for cooking', isDone: false, isEdited: false, }, { desc: 'Wash the dishes and clean the house', isDone: false, isEdited: false, }, ]; let newTodo; function createTodo() { todos = [...todos, {desc: newTodo, isDone: false, isEdited: false}]; newTodo = null; } // 修改函数,接收整个todo对象 function editTodo(todo) { todo.isEdited = true; } function deleteTodo(desc) { todos = todos.filter(todo => todo.desc !== desc); } $: console.log(todos); </script> <h1> Todoapp </h1> <form on:submit|preventDefault={createTodo}> <label for='create-todo' class='create-todo-label'> Create a new todo: </label> <input bind:value={newTodo} type='text' placeholder='Do something' id='create-todo' required /> <button> Create </button> </form> {#if todos.length !== 0} <h2> Your todos: </h2> {/if} <ul> <!-- 修改each循环,直接使用todo对象引用 --> {#each todos as todo, index} <li> <label for='{index}' class:done={todo.isDone}> {todo.desc} </label> <input id='{index}' bind:checked={todo.isDone} type='checkbox' /> </li> <!-- 点击时传递整个todo对象 --> <button on:click={() => editTodo(todo)}> Edit </button> {#if todo.isEdited} <textarea cols='30' rows='5' bind:value={todo.desc} /> {/if} <button on:click={() => deleteTodo(todo.desc)}> Delete </button> {/each} </ul> <style> .create-todo-label { margin-block-end: 0.25rem; } label { max-inline-size: fit-content; } label.done { text-decoration: line-through; } </style>
补充说明
如果希望保留原有的解构写法,也可以在#each中同时获取整个todo对象:
{#each todos as todo, index} <!-- 解构属性的同时保留todo引用 --> {#const { desc, isDone, isEdited } = todo} <!-- 后续代码可以继续使用desc、isDone、isEdited,同时传递todo给editTodo --> <button on:click={() => editTodo(todo)}>Edit</button> {/each}
内容的提问来源于stack exchange,提问作者Thilo
相关产品推荐
相关产品推荐

