Vue3+element-plus 实现table列表中“行的上下移”

420 阅读1分钟

Vue3+element-plus 实现table列表中“行的上下移”

el-tabel 列表实现行上下移功能:在上移和下移两个按钮中嵌套element-plus自带的icon而实现。

scope中有三个参数(row,cow,$index)分别表示行内容、列内容,以及此行的索引值,el-table上绑定数组 :data=“tableData.data”。

上移和下移两个按钮分别嵌套<Top /><Bottom />的icon组件,并绑定点击函数setOrder(),将此行的行内容(scope.row)和场景卡片顺序操作的action字段(action = "up" or "down")作为参数:

实例

<!-- 使用方式 -->
<template>
    <el-table
      :data="tableData.data"
      stripe
      :border="false"
      class="min-w-1280px"
    >
      <el-table-column
        prop="unique_id"
        label="场景ID"
        width="100"
      />
      <el-table-column
        prop="name"
        label="场景名称"
      />
      <el-table-column label="场景封面图">
        <template #default="scope">
          <el-image
            class="w-100px h-100px z-999"
            :src="scope.row.pic_url"
            :preview-teleported="true"
            :preview-src-list="[scope.row.pic_url]"
            fit="fill"
          />
        </template>
      </el-table-column>
      <el-table-column label="场景加载图">
        <template #default="scope">
          <el-image
            class="w-100px h-100px z-999"
            :src="scope.row.load_pic_url"
            :preview-teleported="true"
            :preview-src-list="[scope.row.load_pic_url]"
            fit="fill"
          />
        </template>
      </el-table-column>
      <el-table-column
        prop="description"
        label="场景简介"
      />
      <el-table-column
        label="操作"
        width="250"
      >
        <template #default="scope">
          <el-space>
            <el-button
              type="text"
              style="padding:0"
              class="ml-5"
              :disabled="scope.$index === 0 && getSceneParam.pn === 1"
              @click="setOrder(scope.row, SetSceneOrder['上移'])"
            >
              <el-icon
                :size="20"
                :color="scope.$index === 0 && getSceneParam.pn === 1 ? '#D8D8D8' : '#2747ED'"
                :class="scope.$index === 0 && getSceneParam.pn === 1 ? '' : 'cursor-pointer'"
              >
                <Top />
              </el-icon>
            </el-button>
            <el-button
              type="text"
              style="padding:0"
              :disabled="(scope.$index + 1) === tableData.data.length && getSceneParam.pn === Math.ceil(tableData.total/getSceneParam.ps) "
              @click="setOrder(scope.row, SetSceneOrder['下移'])"
            >
              <el-icon
                :size="20"
                :color="
                  (scope.$index + 1) === tableData.data.length && getSceneParam.pn === Math.ceil(tableData.total/getSceneParam.ps) ? '#D8D8D8' : '#2747ED'
                "
                :class="
                  (scope.$index + 1) === tableData.data.length && getSceneParam.pn === Math.ceil(tableData.total/getSceneParam.ps) ? '' : 'cursor-pointer'
                "
              >
                <Bottom />
              </el-icon>
            </el-button>
          </el-space>
        </template>
      </el-table-column>
    </el-table>
    <pm-pagination
      class="sticky bottom-0 bg-white"
      :req-param="getSceneParam"
      :list="tableData"
      @size-change="size => getSceneParam.ps = size"
      @current-change="current => getSceneParam.pn = current"
    />
</template>

<script setup lang='ts'>
import * as API from '~/core/types';
import { reactive, watch } from 'vue';
import { getScenesList, setSceneOrder } from '~/core/api';
import { FormStatus, SetSceneOrder } from '~/core/types';
import { Scene } from '~/components';
import { PmMessage, PmPagination } from '~/core/components';
import { Bottom, Top } from '@element-plus/icons-vue';

const tableData = reactive<API.scenesListRes>({
  data: [],
  total: 0
});

const getSceneParam = reactive<API.getScenesListParams>({
  ps: 20,
  pn: 1,
  s: '',
  o: 0,
  status: 0
});

const getScenes = async () => {
  const { data, total } = await getScenesList(getSceneParam, { timeStamp: true });
  tableData.data = data;
  tableData.total = total;
};

const setOrderParam = reactive<API.setSceneOrderParam>({
  sid: 0,
  action: ''
});

const setOrder = async (row: API.scenesListRow, action:string) => {
  setOrderParam.sid = row.unique_id;
  setOrderParam.action = action;
  await setSceneOrder(setOrderParam);
  await getScenes();
  PmMessage({ message: '设置成功', duration: 1000 });
};


watch([() => getSceneParam.o, () => getSceneParam.pn, () => getSceneParam.ps, () => getSceneParam.status], (cur, pre) => {
  getScenes();
}, { immediate: true });
</script>

<style>
</style>

注意:当table列表有分页功能时要注意边界情况,即列表的第一行无法实现上移,列表的最后一行无法实现下移。

列表的第一行:disabled="scope.$index === 0 && getSceneParam.pn === 1"

列表的最后一行:disabled="(scope.$index + 1) === tableData.data.length && getSceneParam.pn === Math.ceil(tableData.total/getSceneParam.ps) "

当最后一行的索引值(scope.$index + 1)等于table列表的总长度(tableData.data.length),且分页的页数(getSceneParam.pn) 等于 表格的总条数除以每页的条数后采用 Math.ceil()四舍五入并返回大于等于给定数字的最小整数 Math.ceil(tableData.total/getSceneParam.ps)时,下移采用禁用状态。

效果

image.png

types参数定义代码

//types-->scene.ts
import { UserSceneStatus } from '~/core/types';
import { listData } from './common';

export type getScenesListParams = {
  ps: number;
  pn: number;
  s: string;
  o: number;
  status: number;
};

export type scenesListRow = {
  unique_id: number;
  name: string;
  description: string;
  pic_url: string;
  load_pic_url: string;
  tpl_id: number;
  audit_by: number;
};

export type scenesListRes = listData<scenesListRow>;

export type setSceneOrderParam = {
  sid: number;
  action: string;
};

api接口请求代码

//api-->scene.ts
import * as API from '~/core/types';
import request from './request';
import { pick } from 'lodash-es';

/** 获取场景列表 */
export const getScenesList = async (
  params: API.getScenesListParams,
  options: { timeStamp: boolean }
) =>
  request<API.scenesListRes>({
    url: '/scene-admin/v1/scenes',
    method: 'GET',
    params,
    ...(options || {})
  });

/** 重新排序场景顺序 */
export const setSceneOrder = async (data: API.setSceneOrderParam) =>
  request<string>({
    url: '/scene-admin/v1/scenes/reorder',
    method: 'POST',
    data
  });

types枚举代码

action字段采用枚举的形式实现:action = "up" or "down"

//types-->enum.ts
/** 场景卡片顺序操作类别 */
export enum SetSceneOrder {
  '上移'='up',
  '下移'='down'
}