如何在Vuex中通过复选框修改循环中对象的指定属性
问题:修改Vuex中todos数组指定对象的completed属性
我有一个包含所需状态的todosModule,todos数组中存储着对象。当我循环渲染这些对象时,需要在复选框状态改变时,修改循环中对应对象的completed属性(该属性为布尔类型)。
原代码文件
1. todosModule.js(Vuex模块)
import axios from "axios"; export const todosModule = { state: () => ({ todos: [], page: 1, limit: 10, totalPages: 0, isTodosLoading: false }), getters: { }, mutations: { setTodos(state, todos) { state.todos = todos }, setPage(state, page) { state.page = page }, setTotalPages(state, totalPages) { state.totalPages = totalPages }, setLoadingTodos(state, bool) { state.isTodosLoading = bool }, setCompleted(state, completed) { console.log(state.todos.completed) state.todos.completed = completed } }, actions: { async fetchTodos({state, commit}) { try { commit('setLoadingTodos' , true) const response = await axios.get('https://jsonplaceholder.typicode.com/todos', { params: { _page: state.page, _limit: state.limit } }) commit('setTotalPages', Math.ceil(response.headers['x-total-count'] / state.limit)) commit('setTodos', response.data) } catch (e) { console.log(e) } finally { commit('setLoadingTodos', false) } } }, namespaced: true }
2. TodoItem.vue(子组件)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <template> <div class="col"> <div class="card"> <div class="card-body" :class="todo.completed ? 'bg-light' : ''"> <div class="d-flex align-self-center justify-content-between"> <h5 class="card-title">{{todo.title}}</h5> <div class="form-check form-switch"> <input class="form-check-input" type="checkbox" id="flexSwitchCheckChecked" @change="setCompleted" :checked="todo.completed"> </div> </div> <p v-if="todo.completed === true" class="card-text text-success">Выполнено</p> <p v-else class="card-text text-danger">Невыполнено</p> <div class="d-flex align-content-center justify-content-between"> <div class="btn-list"> <button-bootstrap css-class="btn-primary">Изменить</button-bootstrap> <button-bootstrap css-class="btn-danger">Удалить</button-bootstrap> </div> <div class="card-date d-inline-flex text-muted"> <span class="align-self-center">id {{todo.id}}</span> </div> </div> </div> </div> </div> </template> <script> import ButtonBootstrap from "@/components/UI/ButtonBootstrap"; export default { name: "TodoItem", components: {ButtonBootstrap}, props: { todo: { type: Object, required: true } }, methods: { setCompleted(event) { this.$store.commit('todos/setCompleted', event.target.checked) }, } } </script> <style lang="scss" scoped> .form-switch .form-check-input { margin-left: 0; } .btn-list { button:first-child { margin-right: 1rem; } } </style>
3. TodoList.vue(父组件)
<template> <div class="row row-cols-1 g-4"> <TodoItem v-for="todo in todos" :todo="todo" :key="todo.id"/> </div> </template> <script> import TodoItem from "@/components/TodoItem"; export default { name: "TodoList", components: {TodoItem}, props: { todos: { type: Array, required: true, } } } </script> <style lang="scss" scoped> .row { margin-top: 2rem; } </style>
解决方案
1. 修改todosModule.js中的setCompleted mutation
setCompleted(state, payload) { const index = state.todos.findIndex(todo => todo.id === payload.id); state.todos[index].completed = payload.completed }
2. 修改TodoItem.vue中的复选框事件和方法
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <template> <div class="col"> <div class="card"> <div class="card-body" :class="todo.completed ? 'bg-light' : ''"> <div class="d-flex align-self-center justify-content-between"> <h5 class="card-title">{{todo.title}}</h5> <div class="form-check form-switch"> <input class="form-check-input" type="checkbox" id="flexSwitchCheckChecked" @change="setCompleted($event, todo.id)" :checked="todo.completed"> </div> </div> <p v-if="todo.completed === true" class="card-text text-success">Выполнено</p> <p v-else class="card-text text-danger">Невыполнено</p> <div class="d-flex align-content-center justify-content-between"> <div class="btn-list"> <button-bootstrap css-class="btn-primary">Изменить</button-bootstrap> <button-bootstrap css-class="btn-danger">Удалить</button-bootstrap> </div> <div class="card-date d-inline-flex text-muted"> <span class="align-self-center">id {{todo.id}}</span> </div> </div> </div> </div> </div> </template> <script> import ButtonBootstrap from "@/components/UI/ButtonBootstrap"; export default { name: "TodoItem", components: {ButtonBootstrap}, props: { todo: { type: Object, required: true } }, methods: { setCompleted(event, id) { this.$store.commit('todos/setCompleted', {completed: event.target.checked , id: id}); }, } } </script> <style lang="scss" scoped> .form-switch .form-check-input { margin-left: 0; } .btn-list { button:first-child { margin-right: 1rem; } } </style>
核心说明
原代码的问题在于setCompleted mutation直接给todos数组添加了completed属性,而非修改数组内指定对象的属性。修改后:
- 子组件复选框触发事件时,同时传递事件对象和当前todo的id
- 提交mutation时,传入包含
id和completed状态的对象作为参数 - 在mutation中,通过
findIndex定位到对应id的todo,再修改其completed属性
内容的提问来源于stack exchange,提问作者bobrov_site
相关产品推荐
相关产品推荐

