You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Vuetify数据表格行内编辑时正确更新Vuex状态?

Vuetify Data Table 行内编辑完整实现(Vue + Vuex)

看起来你正在用Vuetify的v-data-table做课程列表,想要实现行内编辑功能对吧?我把你的代码补全并优化了,结合Vuex来管理状态,确保编辑后的数据能同步到全局状态中,下面是完整的实现方案:


完整 Courses.vue 组件代码

<template>
  <v-data-table
    :headers="headers"
    :items="courses"
    :search="search"
    :loading="loading"
    no-data-text="No Courses Available"
  >
    <template slot="items" slot-scope="props">
      <tr>
        <!-- 课程标题编辑列 -->
        <td>
          <v-edit-dialog
            :return-value.sync="props.item.title"
            lazy
            @save="updateCourse(props.item, 'title')"
            @cancel="resetCourse(props.item)"
          >
            {{ props.item.title }}
            <v-text-field
              slot="input"
              v-model="props.item.title"
              label="Course Title"
              single-line
              counter
              maxlength="50"
            ></v-text-field>
          </v-edit-dialog>
        </td>
        <!-- 课程时长编辑列 -->
        <td>
          <v-edit-dialog
            :return-value.sync="props.item.duration"
            lazy
            @save="updateCourse(props.item, 'duration')"
            @cancel="resetCourse(props.item)"
          >
            {{ props.item.duration }} mins
            <v-text-field
              slot="input"
              v-model="props.item.duration"
              label="Duration (mins)"
              single-line
              type="number"
              min="1"
            ></v-text-field>
          </v-edit-dialog>
        </td>
        <!-- 操作列 -->
        <td>
          <v-btn icon small @click="deleteCourse(props.item.id)">
            <v-icon>mdi-delete</v-icon>
          </v-btn>
        </td>
      </tr>
    </template>
  </v-data-table>
</template>

<script>
import { mapState, mapActions } from 'vuex'

export default {
  name: 'Courses',
  data() {
    return {
      search: '',
      // 保存原始数据用于取消编辑时重置
      originalCourses: {},
      headers: [
        { text: 'Course Title', value: 'title' },
        { text: 'Duration', value: 'duration' },
        { text: 'Actions', value: 'actions', sortable: false }
      ]
    }
  },
  computed: {
    ...mapState({
      courses: state => state.courses.items,
      loading: state => state.courses.loading
    })
  },
  created() {
    // 初始化时拉取课程数据
    this.fetchCourses()
    // 缓存原始数据
    this.cacheOriginalCourses()
  },
  watch: {
    courses() {
      // 课程数据更新时重新缓存原始数据
      this.cacheOriginalCourses()
    }
  },
  methods: {
    ...mapActions({
      fetchCourses: 'courses/fetchCourses',
      updateCourse: 'courses/updateCourse',
      deleteCourse: 'courses/deleteCourse'
    }),
    // 缓存原始课程数据,用于取消编辑时重置
    cacheOriginalCourses() {
      this.originalCourses = this.courses.reduce((acc, course) => {
        acc[course.id] = { ...course }
        return acc
      }, {})
    },
    // 取消编辑时重置数据
    resetCourse(course) {
      Object.assign(course, this.originalCourses[course.id])
    }
  }
}
</script>

Vuex 课程模块代码(store/modules/courses.js)

const state = {
  items: [],
  loading: false
}

const mutations = {
  SET_COURSES(state, courses) {
    state.items = courses
  },
  SET_LOADING(state, status) {
    state.loading = status
  },
  UPDATE_COURSE(state, updatedCourse) {
    const index = state.items.findIndex(course => course.id === updatedCourse.id)
    if (index !== -1) {
      state.items.splice(index, 1, updatedCourse)
    }
  },
  DELETE_COURSE(state, courseId) {
    state.items = state.items.filter(course => course.id !== courseId)
  }
}

const actions = {
  async fetchCourses({ commit }) {
    commit('SET_LOADING', true)
    try {
      // 替换成你的真实API请求
      const response = await this.$axios.get('/api/courses')
      commit('SET_COURSES', response.data)
    } catch (error) {
      console.error('Failed to fetch courses:', error)
    } finally {
      commit('SET_LOADING', false)
    }
  },
  async updateCourse({ commit }, course) {
    commit('SET_LOADING', true)
    try {
      // 替换成你的真实API更新请求
      const response = await this.$axios.put(`/api/courses/${course.id}`, course)
      commit('UPDATE_COURSE', response.data)
    } catch (error) {
      console.error('Failed to update course:', error)
      // 可添加全局错误提示,比如 this.$snackbar.error('更新失败')
    } finally {
      commit('SET_LOADING', false)
    }
  },
  async deleteCourse({ commit }, courseId) {
    commit('SET_LOADING', true)
    try {
      await this.$axios.delete(`/api/courses/${courseId}`)
      commit('DELETE_COURSE', courseId)
    } catch (error) {
      console.error('Failed to delete course:', error)
    } finally {
      commit('SET_LOADING', false)
    }
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

关键实现要点

  • 行内编辑核心:用Vuetify的v-edit-dialog组件,通过:return-value.sync双向绑定字段,点击保存时触发Vuex的updateCourse action提交修改。
  • 数据重置机制:初始化和数据更新时缓存原始数据,取消编辑时快速重置当前行,避免未保存的修改污染全局状态。
  • Vuex状态一致性:所有数据操作(获取、更新、删除)都通过异步action处理,mutation同步更新状态,保证数据在全局的一致性。
  • 用户体验优化:添加输入验证(数字类型、长度限制)、loading状态反馈,让操作更直观。

内容的提问来源于stack exchange,提问作者Adam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:39:17