Vue父子组件通信问题:父组件全选复选框无法同步子组件数据
解决Vue父组件修改props后子组件data不更新的问题
嘿,你遇到的这个问题其实是Vue组件响应式里的常见坑——子组件的data属性是在组件初始化时从props复制的,之后父组件修改props对应的对象属性时,子组件的data不会自动同步,因为data的初始化逻辑只在组件创建时执行一次。
咱们直接看具体的修复方案,结合你的代码来改:
方法1:用计算属性/直接使用props替代子组件的data(推荐)
你完全没必要把props.todo的属性都复制到子组件的data里,直接使用父组件传递的todo props就能自动响应变化。修改子组件代码如下:
<template> <div class="todo-item-container"> <div class="todo-title-container"> <div class="todo-id-container"> <div id="todo-id"> <h2>{{ todo.id }}</h2> </div> </div> <div id="todo-title"><h2>{{ todo.title }}</h2></div> <div class="todo-completed-container"> <a href="#" class="todo-button"> <!-- 用:checked绑定props的completed,避免直接v-model修改props --> <input type="checkbox" :checked="todo.completed" @change="changedCompleted"> </a> </div> <div class="todo-delete-container"> <a href="#" class="todo-button" @click="deletedTodo">×</a> </div> </div> <hr> <div class="todo-body-container"> <p id="todo-body">{{ todo.body }}</p> </div> </div> </template> <script> export default { name: 'TodoItem', props: { todo: { type: Object, required: true, }, index: { type: Number, required: true, }, }, // 删掉子组件的data,直接用props的todo methods: { deletedTodo() { this.$emit('removeTodo', { index: this.index, todo: { ...this.todo } // 用扩展运算符复制todo对象,避免直接修改props }) }, changedCompleted(event) { this.$emit('changedCompleted', { index: this.index, todo: { ...this.todo, completed: event.target.checked // 更新completed状态后传给父组件 } }) }, }, } </script>
这样修改后,子组件直接依赖父组件的todo props,当父组件通过checkAll修改todos里的completed属性时,子组件的视图会自动更新——因为props本身是响应式的。
方法2:监听props变化更新子组件data(如果必须保留data)
如果你因为业务需求一定要保留子组件的data,可以通过watch深度监听todo props的变化,手动同步data:
<script> export default { name: 'TodoItem', props: { todo: { type: Object, required: true, }, index: { type: Number, required: true, }, }, data () { return { id: this.todo.id, title: this.todo.title, body: this.todo.body, completed: this.todo.completed, } }, watch: { todo: { deep: true, // 因为todo是对象,需要开启深度监听 handler(newTodo) { // 当父组件的todo变化时,同步更新子组件的data this.id = newTodo.id this.title = newTodo.title this.body = newTodo.body this.completed = newTodo.completed } } }, methods: { deletedTodo() { this.$emit('removeTodo', { index: this.index, todo: { id: this.id, title: this.title, body: this.body, completed: this.completed, } }) }, changedCompleted() { this.$emit('changedCompleted', { index: this.index, todo: { id: this.id, title: this.title, body: this.body, completed: this.completed, } }) }, }, } </script>
另外,父组件的checkAll方法还有个小问题:event没有作为参数传入,会导致报错,改一下:
checkAll(event) { // 加上event参数 this.todos.forEach((todo) => todo.completed = event.target.checked) }
内容的提问来源于stack exchange,提问作者sammyyy
相关产品推荐
相关产品推荐

