javascript - 为什么删除上面的 todo-item 时,划线的下面的 todo 项会变成划线?
问题描述
当上面的 todo-item 被删除时,为什么划线下面的 todo 项会变成划线?
例如:
项目1 项目2 项目3 项目4
交叉项目3:
项目 1 项目 2 项目 3 X 项目 4
删除第 2 项:
项目 1 项目 3 项目 4 X
我在 Vue 代码中做错了什么?我昨天刚开始学习 Vue,所以我的错误很可能是基本的。
<div id="app">
<todo-list>
</todo-list>
</div>
<style>
.crossed {
text-decoration : line-through;
}
.todo:hover {
cursor: pointer;
font-weight: bold;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('todo-list',{
data: function () {
return {
newText: '',
todos:[],
todoId: 0
}
},
template: `
<div>
<form v-on:submit.prevent="addTodo">
<input v-model="newText">
<button>ADD TODO</button>
</form>
<ul>
<todo class="todo" v-for="(todo,index) in todos" :text="todo.text" :key="todo.todoId" @remove="removeTodo(index)"></todo>
</ul>
</div>
`,
methods: {
addTodo: function() {
this.todos.push({
text: this.newText,
done: false,
id: this.todoId++
});
this.newText = '';
},
removeTodo: function(index) {
this.todos.splice(index,1);
}
}
});
Vue.component('todo',{
props: ['text'],
data: function () {
return {
done: false
}
},
template: `
<li>
<span v-on:click="done = !done" :class="{crossed: done}">
{{text}}
</span>
<button v-on:click="$emit('remove')">Remove</button>
</li>
`
})
new Vue({
el: '#app'
})
</script>
解决方案
您在孩子的 todo 组件中切换完成值。最好确保只有一个单一的事实来源。应该在父数据属性 todos 中。
我所做的是将 todo 对象作为道具传递给子 todo 组件。按下完成后,像删除事件一样发出事件,也像删除事件一样更改父级的完成值。
编辑以进一步解释:
下面是您的子待办事项组件。
Vue.component('todo',{
props: ['text'],
data: function () {
return {
done: false
}
},
template: `
<li>
<span v-on:click="done = !done" :class="{crossed: done}">
{{text}}
</span>
<button v-on:click="$emit('remove')">Remove</button>
</li>
`
})
“完成”在数据属性中声明,而不是从道具传递下来。
您实际上是在声明一个全新的“done”,我将其称为“childDone”,这个“childDone”与您的父 todos 数组“done”无关。这个“childDone”只存在于这个组件中,所以当你切换这个“childDone”的值时,父母的待办事项“done”不会受到影响。
是的,UI 显示待办事项已被越过,因为您的 UI 还指的是“childDone”而不是父级“done”。父级“完成”从未传递,因此子 todo 组件不使用父级的“完成”渲染
要解释为什么删除第2项,第4项会变成划线。
- todos.length = 4,渲染 4 个组件
- 组件 1:todo1:childDone=false
- 组件 2:todo2:childDone=false
- 组件 3:todo3:childDone=false
- 组件 4:todo4:childDone=false
- 越过第三个分量,
- 组件 1:todo1:childDone=false
- 组件 2:todo2:childDone=false
- 组件 3:todo3:childDone=true
- 组件 4:todo4:childDone=false
- 删除第二个 todo 元素,todos.length = 3,渲染 3 个组件
- 组件 1:todo1:childDone=false
- 组件 2:todo3:childDone=false
- 组件 3:todo4:childDone=true
compoenent4(不再渲染,因为 todos.length = 3)
<div id="app">
<todo-list>
</todo-list>
</div>
<style>
.crossed {
text-decoration : line-through;
}
.todo:hover {
cursor: pointer;
font-weight: bold;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('todo-list',{
data: function () {
return {
newText: '',
todos:[],
todoId: 0
}
},
template: `
<div>
<form v-on:submit.prevent="addTodo">
<input v-model="newText">
<button>ADD TODO</button>
</form>
<ul>
<todo class="todo" v-for="(todo,index) in todos" :todo="todo" :key="todo.todoId" @remove="removeTodo(index)" @done="doneTodo(index)"></todo>
</ul>
</div>
`,
methods: {
addTodo: function() {
this.todos.push({
text: this.newText,
done: false,
id: this.todoId++
});
this.newText = '';
},
removeTodo: function(index) {
this.todos.splice(index,1);
},
doneTodo: function(index) {
this.todos[index].done = !this.todos[index].done;
}
}
});
Vue.component('todo',{
props: ['todo'],
template: `
<li>
<span v-on:click="$emit('done')" :class="{crossed: todo.done}">
{{todo.text}}
</span>
<button v-on:click="$emit('remove')">Remove</button>
</li>
`
})
new Vue({
el: '#app'
})
</script>
推荐阅读
- c++ - 如何设置 VSCode C++ 以显示局部变量
- python - Python如何多次但按顺序打印列表?
- ios - 将字符串写入 iOS 文档目录中的文本文件没有错误但不起作用
- python - 交换语言时键盘模块热键中断(Microsoft IME)
- r - 如何使用几列的命令 summarise() 和 group_by() 确定 R 中每列的平均值?
- electron - Electron——如何让我的程序自动更新到原来的安装目录?
- c - 如果使用连接字符串,则打印 DataGrid WPF
- docker - GatsbyJS - 如何解决 GatsbyJS 的“net::ERR_CONNECTION_REFUSED”?
- rust - 如何为任何给定请求重用 Tower::ServiceBuilder
- php - 如何停止下载整个网站以及如何加密网站