You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
shop-admin/admin/src/components/extra/ElTable.vue

301 lines
9.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<component :is="render" />
</template>
<script setup lang="jsx">
import { ElTable } from 'element-plus/es/components/table/index';
import 'element-plus/es/components/table/style/css';
import Sortable from 'sortablejs';
const props = defineProps({
/**
* 是否可拖拽排序
*/
sortable: {
type: Boolean,
default: false,
},
/**
* 拖拽表格唯一标识,用于区分多个拖拽区域互相拖拽时数据来源
*/
code: {
type: String,
default: '',
},
/**
* el-table原生属性表格数据代理element原生属性用于修改数据为排序后的数据
*/
data: {
type: Array,
required: true,
},
/**
* el-table原生属性唯一标识属性字段名默认id
*/
rowKey: {
type: String,
default: 'id',
},
/**
* 排序属性字段名默认sort
*/
sortKey: {
type: String,
default: 'sort',
},
/**
* 控制是否修改表格数据排序,默认修改,如果不修改则只改变表格渲染顺序但是真实数据顺序不变
*/
modifyData: {
type: Boolean,
default: true,
},
/**
* sortablejs原生属性分组详细用法见官方文档
* http://www.sortablejs.com/options.html#:~:text=group%EF%BC%9Astring%20or%20object
*/
group: {
type: [String, Object],
default: '',
},
/**
* sortablejs原生属性是否列表单元
*/
sort: {
type: Boolean,
default: true,
},
/**
* sortablejs原生属性是否此sortable对象是否可用
*/
disabled: {
type: Boolean,
default: false,
},
/**
* sortablejs原生属性动画持续时间
*/
animation: {
type: Number,
default: 150,
},
/**
* sortablejs原生属性可拖拽元素
*/
draggable: {
type: String,
default: 'el-table__row',
},
/**
* sortablejs原生属性元素可拖拽部分选择器默认为空表示元素任意部分都可拖拽
*/
handle: {
type: String,
default: '',
},
/**
* sortablejs原生属性幽灵元素
*/
ghostClass: {
type: String,
default: 'ghost-row',
},
/**
* sortablejs原生属性选中的元素
*/
chosenClass: {
type: String,
default: 'chosen-row',
},
/**
* sortablejs原生属性拖拽的元素
*/
dragClass: {
type: String,
default: 'drag-row',
},
/**
* sortablejs原生属性不允许拖拽元素选择器
*/
filter: {
type: String,
default: '.ignore-drag-sort',
},
});
const attrs = useAttrs();
const slots = useSlots();
const emits = defineEmits(['row-sort', 'row-add', 'row-remove', 'row-clone', 'expand-change']);
// 可拖拽表格唯一标识
const uid = 'sortableTable' + getCurrentInstance().uid;
const { proxy } = getCurrentInstance();
// 表格ref
const sortting = ref(false);
const refsTable = ref(null);
const expandRowKeys = ref([]);
const handleExpandChange = (row, expandRows) => {
expandRowKeys.value = expandRows.map((item) => item[props.rowKey]);
emits('expand-change', row, expandRows);
};
// sortablejs实例
let sortable = ref(null);
// 初始化sortablejs
const handleInit = () => {
// 获取拖拽区域元素
const el = document.querySelector(`[sort-id='${uid}'] :not(.el-table) tbody`);
if (el) {
sortable.value = new Sortable(el, {
group: props.group,
sort: props.sort,
disabled: !props.sortable || props.disabled,
animation: props.animation,
draggable: '.' + props.draggable,
handle: props.handle,
ghostClass: props.ghostClass,
chosenClass: props.chosenClass,
dragClass: props.dragClass,
filter: props.filter,
onUpdate(e) {
if (typeof e.newIndex === 'number') {
if (props.modifyData) {
// 开始对数据进行重新排序
const row = unref(props.data).splice(e.oldIndex, 1)[0];
unref(props.data).splice(e.newIndex, 0, row);
// 刷新排序属性
unref(props.data).forEach((item, index) => {
item[props.sortKey] = index + 1;
});
proxy.$nextTick(() => {
// 排序完成
proxy.$nextTick(() => {
proxy.$forceUpdate();
// 触发排序完成事件
emits('row-sort', e.newIndex, e.oldIndex, e);
});
});
} else {
// 触发排序完成事件
emits('row-sort', e.newIndex, e.oldIndex, e);
}
}
},
setData(dataTransfer) {
dataTransfer.setData('code', props.code);
},
onAdd(e) {
// 从sort-id为这个的表格里面拖过来的元素需要自行根据表格元素判断数据来源
let code = e.originalEvent.dataTransfer.getData('code');
// 触发添加元素事件
emits(
'row-add',
e.newIndex,
e.oldIndex,
code,
(row) => {
if (props.modifyData && row) {
sortting.value = true;
unref(props.data).splice(e.newIndex, 0, row);
// 通过v-if强行重新渲染表格否则表格可能渲染错误
proxy.$nextTick(() => {
sortting.value = false;
proxy.$nextTick(() => {
handleInit();
});
});
}
},
e
);
},
onRemove(e) {
if (typeof e.newIndex === 'number') {
if (props.modifyData && e.pullMode !== 'clone') {
unref(props.data).splice(e.oldIndex, 1);
proxy.$forceUpdate();
}
// 触发添加元素事件
emits('row-remove', e.newIndex, e.oldIndex, e);
}
},
onClone(e) {
if (typeof e.newIndex === 'number') {
// 触发赋值元素事件
emits('row-clone', e.newIndex, e.oldIndex, e);
}
},
});
} else {
console.error('可拖拽表格ID不存在');
}
};
// 元素实例化后初始化sortablejs
onMounted(handleInit);
// 代理原生函数
const handleProxy = (fnName, args) => {
return unref(refsTable)[fnName]?.apply(unref(refsTable), args);
};
const clearSelection = function () {
return handleProxy('clearSelection', arguments);
};
const toggleRowSelection = function () {
return handleProxy('toggleRowSelection', arguments);
};
const toggleAllSelection = function () {
return handleProxy('toggleAllSelection', arguments);
};
const toggleRowExpansion = function () {
return handleProxy('toggleRowExpansion', arguments);
};
const setCurrentRow = function () {
return handleProxy('setCurrentRow', arguments);
};
const clearSort = function () {
return handleProxy('clearSort', arguments);
};
const clearFilter = function () {
return handleProxy('clearFilter', arguments);
};
const doLayout = function () {
return handleProxy('doLayout', arguments);
};
const sort = function () {
return handleProxy('sort', arguments);
};
// 抛出
defineExpose({
refsTable,
clearSelection,
toggleRowSelection,
toggleAllSelection,
toggleRowExpansion,
setCurrentRow,
clearSort,
clearFilter,
doLayout,
sort,
});
const render = () => (
<ElTable
ref={refsTable}
{...props}
{...attrs}
class={{ 'sortable-table': true, [props.group]: true }}
expand-row-keys={unref(expandRowKeys)}
row-key={props.rowKey}
sort-id={unref(uid)}
onExxpandChange={() => handleExpandChange}
v-slots={unref(sortting) ? {} : slots}
/>
);
</script>
<style lang="less" scoped>
:deep(.ghost-row) {
background: #ddd;
}
:deep(.chosen-row) {
background: #eee;
}
:deep(.drag-row) {
background: #ccc;
}
</style>