Vue2 + ElementUI 批量更新排序/产品分类完整实现

Vue2 + ElementUI 批量更新排序/产品分类完整实现

分两种场景:批量拖拽排序批量勾选修改分类,适配你产品列表分页场景,编辑返回保留页码逻辑不变。

一、批量拖拽排序(el-table 行拖拽)

1. 安装拖拽依赖 sortablejs

bash 复制代码
npm i sortablejs --save

2. 表格组件代码

vue 复制代码
<template>
  <div>
    <el-table
      ref="table"
      :data="tableData"
      border
      row-key="id"
    >
      <el-table-column label="排序" width="80">
        <template slot-scope="{ row }">
          <i class="el-icon-sort" style="cursor:move;color:#999"></i>
        </template>
      </el-table-column>
      <el-table-column prop="name" label="产品名称"></el-table-column>
      <el-table-column prop="sort" label="当前排序值"></el-table-column>
    </el-table>

    <el-button type="primary" @click="batchSaveSort">批量保存排序</el-button>
  </div>
</template>

<script>
import Sortable from 'sortablejs'
export default {
  data() {
    return {
      tableData: [],
      // 拖拽后新排序数组
      sortList: []
    }
  },
  mounted() {
    this.initDrag()
  },
  methods: {
    // 初始化拖拽
    initDrag() {
      const el = this.$refs.table.$el.querySelector('.el-table__body-wrapper tbody')
      Sortable.create(el, {
        animation: 150,
        ghostClass: 'sort-ghost',
        onEnd: ({ newIndex, oldIndex }) => {
          // 拖拽完成记录新顺序
          this.sortList = this.tableData.map((item, idx) => ({
            id: item.id,
            sort: idx + 1 // 排序值从1自增
          }))
        }
      })
    },
    // 批量提交排序接口
    async batchSaveSort() {
      if (!this.sortList.length) {
        this.$message.warning('未调整排序')
        return
      }
      const res = await this.$api.product.batchSort(this.sortList)
      if (res.code === 0) {
        this.$message.success('排序更新成功')
        // 刷新当前页列表(保留分页)
        this.getList()
        this.sortList = []
      }
    },
    // 请求列表(原有分页逻辑不变)
    getList() {
      // ...你的分页请求代码
    }
  }
}
</script>

<style scoped>
::v-deep .sort-ghost {
  background: #ecf5ff !important;
}
</style>

后端接口传参格式

js 复制代码
// sortList 传给后端
[
  { id: 101, sort: 1 },
  { id: 105, sort: 2 },
  { id: 103, sort: 3 }
]

二、批量勾选修改产品分类(最常用批量操作)

1. 表格+批量操作按钮

vue 复制代码
<template>
  <div>
    <!-- 批量操作区 -->
    <el-button type="warning" @click="openBatchCateDialog">批量修改分类</el-button>

    <el-table
      ref="table"
      :data="tableData"
      border
      row-key="id"
      @selection-change="handleSelectionChange"
    >
      <!-- 多选框 -->
      <el-table-column type="selection" width="55"></el-table-column>
      <el-table-column prop="name" label="产品名称"></el-table-column>
      <el-table-column prop="cateName" label="所属分类"></el-table-column>
    </el-table>

    <!-- 批量修改分类弹窗 -->
    <el-dialog title="批量修改分类" :visible.sync="batchDialogVisible" width="400px">
      <el-select v-model="batchCateId" placeholder="请选择分类">
        <el-option
          v-for="item in cateList"
          :key="item.id"
          :label="item.name"
          :value="item.id"
        ></el-option>
      </el-select>
      <div slot="footer" class="dialog-footer">
        <el-button @click="batchDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="confirmBatchCate">确定修改</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tableData: [],
      multipleSelection: [], // 选中行数组
      batchDialogVisible: false,
      batchCateId: '', // 批量选中分类ID
      cateList: [] // 全部分类下拉数据
    }
  },
  methods: {
    // 勾选事件
    handleSelectionChange(val) {
      this.multipleSelection = val
    },
    // 打开批量弹窗
    openBatchCateDialog() {
      if (!this.multipleSelection.length) {
        this.$message.warning('请先勾选要修改的产品')
        return
      }
      this.batchCateId = ''
      this.batchDialogVisible = true
    },
    // 确认批量修改分类
    async confirmBatchCate() {
      if (!this.batchCateId) {
        this.$message.warning('请选择分类')
        return
      }
      // 提取勾选产品id数组
      const ids = this.multipleSelection.map(item => item.id)
      const params = {
        ids,
        cateId: this.batchCateId
      }
      const res = await this.$api.product.batchUpdateCate(params)
      if (res.code === 0) {
        this.$message.success('批量修改成功')
        this.batchDialogVisible = false
        this.multipleSelection = [] // 清空勾选
        this.$refs.table.clearSelection() // 清空表格勾选框
        // 刷新当前分页列表(保留第二页不跳回第一页)
        this.getList()
      }
    },
    getList() {
      // 原有分页请求逻辑
    }
  }
}
</script>

后端批量接口参数

js 复制代码
{
  ids: [101,102,103], // 批量产品ID数组
  cateId: 5 // 目标分类ID
}

三、结合你之前「编辑返回丢失页码」问题配套处理

1. keep-alive 缓存列表 + 批量操作刷新不丢页

js 复制代码
// 列表页 activated 钩子,从编辑/批量弹窗回来自动刷新
activated() {
  // 批量修改、编辑完成后都会重新请求当前页数据
  this.getList()
}

2. 如果不用 keep-alive,分页参数统一存 query

批量操作成功后不用 router.back(),直接刷新当前路由:

js 复制代码
// 批量成功后刷新列表,保留页码
this.$router.push({
  path: '/product/list',
  query: {
    page: this.pageNum,
    size: this.pageSize
  }
})

四、常用拓展功能

  1. 批量删除
    和批量改分类逻辑一致,拿到 ids 数组调用删除接口,成功刷新列表。
  2. 批量上下架
    增加下拉选择状态,传 ids + status 批量更新。
  3. 拖拽排序分页兼容问题
  • 拖拽仅作用当前页数据,跨页排序不推荐前端处理;
  • 如需全局统一排序,后端提供全局拖拽接口,分页只展示当前区间。

五、踩坑点

  1. sortablejs 绑定tbody,不要绑定table,否则拖拽失效;
  2. 批量操作后必须 clearSelection(),否则勾选状态残留;
  3. 分页第二页批量更新后,调用 getList() 即可保持当前页码,不会重置pageNum=1;
  4. query 参数是字符串,请求接口时记得转数字 Number(this.$route.query.page)