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

Vue.js类Excel编辑器实现单元格修改后自动更新数据库

问题描述

我希望构建一个具备Excel功能的简易编辑器,要求单元格值变更时数据自动保存至数据库。目前我的实现是编辑单元格后需点击保存按钮才能更新数据库中的值,我是新手,恳请提供帮助🙏。以下是相关代码(并非完整代码,但希望能有所帮助):

HTML 代码

<div>
  <v-toolbar>
    <v-dialog>
      <template #activator="{ on, attrs }">
        <v-btn
          color="orange"
          dark
          depressed
          :loading="exportCSVLoader"
          class="mb-2 mx-2"
          @click="exportCSV"
        >
          导出
        </v-btn>
        <ImportCSV
          :import-c-s-v-loader="importCSVLoader"
          @csv-data="getImportFileData"
        />

        <v-btn
          color="primary"
          dark
          depressed
          class="mb-2"
          v-bind="attrs"
          v-on="on"
        >
          添加新条目
        </v-btn>
        <v-btn
          dark
          color="red"
          :loading="deleteButtonLoader"
          depressed
          class="mb-2 mx-1"
          @click="deleteItem(deleteItemRow)"
        >
          删除
        </v-btn>
        <v-btn
          color="blue"
          dark
          :loading="saveButtonLoader"
          depressed
          class="mb-2 mx-1"
          @click="SaveExcelRecord(editedRow)"
        >
          保存
        </v-btn>
      </template>
      <v-card>
        <v-card-title>
          <span class="text-h5">{{ formTitle }}</span>
        </v-card-title>
        <v-divider></v-divider>
        <v-card-text>
          <v-container>
            <HouseTextFields :edited-item="editedItem" @clear="close" />
          </v-container>
        </v-card-text>
        <v-divider></v-divider>
        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn color="blue darken-1" text @click="close"> 取消 </v-btn>
          <v-btn
            :loading="saveButtonLoader"
            color="blue darken-1"
            text
            @click="save"
          >
            {{ editedItem?.id ? '更新' : '保存' }}
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
    <v-dialog v-model="dialogDelete" max-width="500px">
      <v-card>
        <v-card-title class="text-h5"
          >确定要删除这一行吗?</v-card-title
        >
        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn color="blue darken-1" text @click="closeDelete"
            >取消</v-btn
          >
          <v-btn
            color="blue darken-1"
            text
            :loading="deleteButtonLoader"
            @click="deleteItemConfirm"
            >确定</v-btn
          >
          <v-spacer></v-spacer>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </v-toolbar>
  <v-divider></v-divider>
</div>
<vue-excel-editor
  ref="grid"
  v-model="dataItem"
  :new-if-bottom="false"
  :allow-add-col="true"
  :no-header-edit="true"
  width="100%"
  :localized-label="myLabels"
  filter-row
  @cell-click="onRowDataChange"
  @update="updateRow"
  @select="rowSelected"
>
  ...
</vue-excel-editor>

JavaScript 代码

methods: {
  updateRow(val) {
    if (val && val.length > 0) {
      let arr = []

      val.forEach(row => {
        if (this.dataItem?.length) {
          this.dataItem.find(el => {
            if (el.$id === row.$id) {
              // 删除$id字段
              delete el['$id']

              // 格式化日期
              if (el.builddate)
                el.builddate = moment(el.builddate).format('YYYY-MM-DD')
              if (el.lastrenovation)
                el.lastrenovation = moment(el.lastrenovation).format(
                  'YYYY-MM-DD'
                )

              if (el.created_at)
                el.created_at = moment(el.created_at).format('YYYY-MM-DD')

              if (el.updated_at)
                el.updated_at = moment(el.updated_at).format('YYYY-MM-DD')

              // 添加到数组
              arr.push(el)
            }
          })
        }
      })

      console.log('修改的行数据', arr)
      this.editedRow.data = [...arr]
    }
  },

  async SaveExcelRecord() {
    if (!this.editedRow.data || this.editedRow.data.length === 0) {
      // this.initToast("没有数据需要保存。", "info");
      return 'no data'
    }

    this.saveButtonLoader = true

    try {
      // 假设API支持批量更新
      await axios.post(
        `http://127.0.0.1:8000/api/JsonBulk`,
        this.editedRow.data
      )
      this.initToast('数据已更新并保存!', 'success')

      // 重置编辑状态
      this.editedRow = {
        index: -1,
        data: []
      }

      // 重新加载所有记录
      this.getHouseRecords()

      this.close()
    } catch (error) {
      this.initToast('数据更新失败', 'error')
    } finally {
      this.saveButtonLoader = false
    }
  }
}
解决方案

要实现单元格变更自动保存,核心是利用vue-excel-editor的@update事件,在数据修改时直接触发保存接口,同时加入防抖避免频繁请求:

步骤1:添加防抖函数

防抖可以避免用户连续修改单元格时多次调用接口,在methods中添加:

debounce(func, delay) {
  let timeoutId
  return function(...args) {
    clearTimeout(timeoutId)
    timeoutId = setTimeout(() => func.apply(this, args), delay)
  }
}

步骤2:修改updateRow方法,自动触发保存

修改updateRow,处理完数据后直接调用保存方法,同时用防抖包装:

updateRow(val) {
  if (val && val.length > 0) {
    let arr = []

    val.forEach(row => {
      if (this.dataItem?.length) {
        const el = this.dataItem.find(el => el.$id === row.$id)
        if (el) {
          // 删除$id字段
          delete el['$id']

          // 格式化日期
          if (el.builddate)
            el.builddate = moment(el.builddate).format('YYYY-MM-DD')
          if (el.lastrenovation)
            el.lastrenovation = moment(el.lastrenovation).format('YYYY-MM-DD')
          if (el.created_at)
            el.created_at = moment(el.created_at).format('YYYY-MM-DD')
          if (el.updated_at)
            el.updated_at = moment(el.updated_at).format('YYYY-MM-DD')

          arr.push(el)
        }
      }
    })

    console.log('修改的行数据', arr)
    this.editedRow.data = [...arr]
    // 触发自动保存,防抖300毫秒
    this.debounce(() => this.SaveExcelRecord(), 300)()
  }
}

步骤3:调整保存逻辑(可选)

如果你的API支持单条数据更新,可以单独写一个单条保存方法,减少数据传输:

async saveSingleRow(row) {
  this.saveButtonLoader = true
  try {
    await axios.post(`http://127.0.0.1:8000/api/JsonBulk`, [row])
    this.initToast('数据已保存!', 'success')
    this.getHouseRecords()
  } catch (error) {
    this.initToast('保存失败', 'error')
  } finally {
    this.saveButtonLoader = false
  }
}

然后在updateRow中调用:

// 替换原来的SaveExcelRecord调用
this.debounce(() => {
  arr.forEach(row => this.saveSingleRow(row))
}, 300)()

步骤4:测试效果

现在编辑单元格后,等待300毫秒(可调整延迟时间),系统会自动调用接口保存数据,无需手动点击保存按钮。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 20:58:10