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)时,下移采用禁用状态。
效果
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'
}