【问题标题】:Why does the todo item below a crossed one become crossed when a todo-item above is deleted?为什么删除上面的 todo-item 时,划线的下面的 todo 项会变成划线?
【发布时间】:2020-09-27 11:24:21
【问题描述】:

当上面的待办事项被删除时,为什么下面的待办事项会变成交叉?

例如:

项目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>

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    我怀疑你没有使用:key="todo.id",而是:key="todo.todoId,因此通过替换文本属性拼接第三个使第四个成为第三个。否则它应该可以工作。

    顺便说一句,todo.todoIdundefined

    【讨论】:

    • 我实际上使用了 todo.todoId 作为密钥,正如您在我的问题中的代码 sn-p 中看到的那样。遗憾的是它不起作用:/
    • @TheProgrammer 好的,是的,在我的手机上修复了我的解释;) todo.todoId 未定义
    • 这就是问题所在!谢谢 !没有看到this.todos.push({ text: this.newText, done: false, id: this.todoId++ });中的错字id:应该是todoId:
    【解决方案2】:

    您在孩子的 todo 组件中切换完成值。最好确保只有一个单一的事实来源。应该在父数据属性中,待办事项。

    我所做的是将 todo 对象作为道具传递给子 todo 组件。当 done 被按下时,像 remove 事件一样发出事件,也像 remove 事件一样改变父级的 done 值。


    编辑以作进一步解释:

    下面是你的子 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 个组件
      • component1:todo1:childDone=false
      • component2:todo2:childDone=false
      • component3:todo3:childDone=false
      • component4:todo4:childDone=false
    2. 越过第三个组件,
      • component1:todo1:childDone=false
      • component2:todo2:childDone=false
      • component3:todo3:childDone=true
      • component4:todo4:childDone=false
    3. 删除第二个 todo 元素,todos.length = 3,渲染 3 个组件
      • component1:todo1:childDone=false
      • component2:todo3:childDone=false
      • component3: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>

    【讨论】:

    • 这就是我最终做的 ^^ 但这并不能解释为什么我的原始方法不起作用。我想了解为什么我正在做的事情不能正常工作。毕竟,在点击子组件时,done 仍然正确设置为 false 或 true,因此未交叉或交叉。只有当上面的元素被删除时,下面的元素才会突然交叉,好像完成状态是为数组中的位置保存的,而不是子组件本身。为什么会这样?
    • 我编辑了答案,我尽量解释清楚。
    猜你喜欢
    • 1970-01-01
    • 2021-01-22
    • 1970-01-01
    • 1970-01-01
    • 2016-08-26
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多