技术: ant-design-vue ts vue3.0
需求:
1.任意级进行表格拖拽
2.鼠标滑过进行编辑
效果图
原理:
ant的tree组件基础下进行改写
代码如下:
<template>
<div class="basic-drop-tree-table">
<div class="flex table-head">
<div
v-for="columnsItem in columns"
:key="columnsItem.key"
:style="countColWidth"
class="table-box"
>
{{ columnsItem.title }}
</div>
<p class="table-head-action">操作</p>
</div>
<a-tree
class="draggable-tree"
draggable
block-node
:tree-data="gData"
:fieldNames="fieldNames"
:defaultExpandAll="true"
@drop="onDrop"
>
<template #title="item">
<div class="flex">
<slot name="icon" :iconData="item"></slot>
<div
v-for="bb in columns"
:key="bb.key"
:style="countColWidth"
class="table-box table-row-action"
>
<div v-if="item.change === true" class="flex input-width">
<a-input
:value="item[bb.key]"
@change="inputChange($event, item, bb)"
@press-enter="save(item)"
@blur="save(item)"
/>
</div>
<div v-else>{{ item[bb.key] }}</div>
</div>
<div class="table-row-action">
<a-button v-if="item.change === false" type="link" @click="actionFn(item)">
编辑
</a-button>
<a-button v-else type="link" @click="save(item)">保存</a-button>
<slot name="action" :item="item"></slot>
</div>
</div>
</template>
</a-tree>
</div>
</template>
<script lang="ts" setup>
import type { TreeProps } from 'ant-design-vue/es/tree';
import useTreeData from '@/hooks/component/useTreeData';
import { computed } from 'vue';
const props = defineProps<{
originDate: any[]; //原始表格数据
treeData: TreeProps['treeData']; //树形表格数据
fieldNames: TreeProps['fieldNames']; //替换字段
columns: any[]; // 表头
}>();
const { onDrop, gData } = useTreeData(props.treeData, props.fieldNames);
const countColWidth = computed(() => {
return `width : calc( (100% - 150px) / ${props.columns.length} )`;
});
const emits = defineEmits<{
(e: 'editableSave', treeData: TreeProps['treeData']): void;
}>();
//添加控制可编写状态
props.originDate.forEach((item) => {
item.change = false;
});
/**可编辑 */
const inputChange = ($event, item, bb) => {
item.data[bb.key] = $event.target.value;
emits('editableSave', props.treeData);
};
const save = (item) => {
item.data.change = false;
};
const actionFn = (item) => {
item.data.change = true;
};
</script>
<style lang="scss" scoped>
.basic-drop-tree-table {
border: 1px solid #f0f0f0;
:deep(.ant-tree .ant-tree-treenode) {
padding: 2px 0px;
line-height: 40px;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
}
:deep(.ant-tree-switcher) {
margin: auto 0px;
}
.table-head {
background: #fafafa;
color: #000000d9;
font-weight: 500;
line-height: 40px;
border-bottom: 1px solid #f0f0f0;
padding-left: 24px;
.table-head-action {
margin: auto 0px;
}
}
.table-row-action {
display: flex;
align-items: center;
}
.table-box {
height: 40px;
line-height: 40px;
margin: auto 0px;
}
.input-width {
width: 80%;
}
.tree-title {
display: flex;
align-items: center;
justify-content: space-between;
}
}
</style>
拖拽的hooks:
import type { AntTreeNodeDropEvent, TreeProps } from 'ant-design-vue/es/tree';
import { ref } from 'vue';
const useTreeData = (treeData: TreeProps['treeData'], fieldNames: TreeProps['fieldNames']) => {
type TreeDataItem = any;
const gData = ref<TreeProps['treeData']>(treeData);
const onDrop = (info: AntTreeNodeDropEvent) => {
const dropKey = info.node.key;
const dragKey = info.dragNode.key; //拖拽的id值
const dropPos = (info.node.pos as string).split('-');
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
const loop = (data: TreeProps['treeData'], key: string | number, callback: any) => {
data?.forEach((item, index) => {
if (item[fieldNames.key] === key) {
return callback(item, index, data);
}
if (item.children) {
return loop(item.children, key, callback);
}
});
};
const data = [...gData.value];
// Find dragObject
let dragObj: TreeDataItem;
// 拖拽的那个值,拖拽值的索引,拖拽值所在的数组
loop(data, dragKey, (item: TreeDataItem, index: number, arr: TreeProps['treeData']) => {
arr?.splice(index, 1);
dragObj = item;
});
if (!info.dropToGap) {
// Drop on the content
loop(data, dropKey, (item: TreeDataItem) => {
item.children = item.children || [];
/// where to insert 示例添加到头部,可以是随意位置
item.children.unshift(dragObj);
});
} else if (
(info.node.children || []).length > 0 && // Has children
info.node.expanded && // Is expanded
dropPosition === 1 // On the bottom gap
) {
loop(data, dropKey, (item: TreeDataItem) => {
item.children = item.children || [];
// where to insert 示例添加到头部,可以是随意位置
item.children.unshift(dragObj);
});
} else {
let ar: TreeProps['treeData'] = [];
let i = 0;
loop(data, dropKey, (_item: TreeDataItem, index: number, arr: TreeProps['treeData']) => {
ar = arr;
i = index;
});
if (dropPosition === -1) {
ar.splice(i, 0, dragObj);
} else {
ar.splice(i + 1, 0, dragObj);
}
}
gData.value = data;
console.log('data', data);
};
return { onDrop, gData };
};
export default useTreeData;
git :
git上面有案例
文件:src\views\table\ant\index.vue