首页 > 解决方案 > 为什么删除上面的 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>

标签: javascriptvue.js

解决方案


您在孩子的 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项会变成划线。

  1. todos.length = 4,渲染 4 个组件
    • 组件 1:todo1:childDone=false
    • 组件 2:todo2:childDone=false
    • 组件 3:todo3:childDone=false
    • 组件 4:todo4:childDone=false
  2. 越过第三个分量,
    • 组件 1:todo1:childDone=false
    • 组件 2:todo2:childDone=false
    • 组件 3:todo3:childDone=true
    • 组件 4:todo4:childDone=false
  3. 删除第二个 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>


推荐阅读