mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-11-03 13:44:47 +08:00
feat: 新增 @pureadmin/table 行、列拖拽示例
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import Sortable from "sortablejs";
|
||||
import { ref, onMounted } from "vue";
|
||||
import Sortable, { Swap } from "sortablejs";
|
||||
import draggable from "vuedraggable/src/vuedraggable";
|
||||
import { useAppStoreHook } from "@/store/modules/app";
|
||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||
|
||||
defineOptions({
|
||||
name: "Draggable"
|
||||
});
|
||||
|
||||
const { setSortSwap } = useAppStoreHook();
|
||||
|
||||
const gridLists = ref<Array<Object>>([
|
||||
{ grid: "cn", num: 1 },
|
||||
{ grid: "cn", num: 2 },
|
||||
@@ -39,7 +42,8 @@ const change = (evt): void => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// 使用原生sortable实现元素位置切换
|
||||
if (!useAppStoreHook().sortSwap) Sortable.mount(new Swap());
|
||||
setSortSwap(true);
|
||||
new Sortable(document.querySelector(".cut-container"), {
|
||||
swap: true,
|
||||
forceFallback: true,
|
||||
@@ -121,7 +125,7 @@ onMounted(() => {
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>拖拽实现元素位置切换</span>
|
||||
<span>拖拽实现元素位置交换</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 拖拽实现元素位置切换 -->
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
import {
|
||||
Base,
|
||||
Stripe,
|
||||
Border,
|
||||
Status,
|
||||
FixHeader,
|
||||
FixColumn,
|
||||
FluidHeight,
|
||||
GroupHeader,
|
||||
Radio,
|
||||
MultipleChoice,
|
||||
Sortable,
|
||||
Filters,
|
||||
ColumnTemplate,
|
||||
HeaderRenderer,
|
||||
Expand,
|
||||
TreeTable,
|
||||
TotalRow,
|
||||
Merge,
|
||||
CustomIndex,
|
||||
Layout,
|
||||
NestProp,
|
||||
ImgPreview
|
||||
} from "./components";
|
||||
import Base from "./base.vue";
|
||||
import Stripe from "./stripe.vue";
|
||||
import Border from "./border.vue";
|
||||
import Status from "./status.vue";
|
||||
import FixHeader from "./fixHeader.vue";
|
||||
import FixColumn from "./fixColumn.vue";
|
||||
import FluidHeight from "./fluidHeight.vue";
|
||||
import GroupHeader from "./groupHeader.vue";
|
||||
import Radio from "./radio.vue";
|
||||
import MultipleChoice from "./multipleChoice.vue";
|
||||
import Sortable from "./sortable.vue";
|
||||
import Filters from "./filters.vue";
|
||||
import ColumnTemplate from "./column-template/index.vue";
|
||||
import HeaderRenderer from "./header-renderer/index.vue";
|
||||
import Expand from "./expand.vue";
|
||||
import TreeTable from "./tree.vue";
|
||||
import TotalRow from "./totalRow.vue";
|
||||
import Merge from "./merge.vue";
|
||||
import CustomIndex from "./customIndex.vue";
|
||||
import Layout from "./layout.vue";
|
||||
import NestProp from "./nestProp.vue";
|
||||
import ImgPreview from "./imgPreview.vue";
|
||||
|
||||
const rendContent = (val: string) =>
|
||||
`代码位置:src/views/pure-table/components/${val}.vue`;
|
||||
`代码位置:src/views/pure-table/base/${val}.vue`;
|
||||
|
||||
export const list = [
|
||||
{
|
||||
@@ -1,47 +0,0 @@
|
||||
import Base from "./base.vue";
|
||||
import Stripe from "./stripe.vue";
|
||||
import Border from "./border.vue";
|
||||
import Status from "./status.vue";
|
||||
import FixHeader from "./fixHeader.vue";
|
||||
import FixColumn from "./fixColumn.vue";
|
||||
import FluidHeight from "./fluidHeight.vue";
|
||||
import GroupHeader from "./groupHeader.vue";
|
||||
import Radio from "./radio.vue";
|
||||
import MultipleChoice from "./multipleChoice.vue";
|
||||
import Sortable from "./sortable.vue";
|
||||
import Filters from "./filters.vue";
|
||||
import ColumnTemplate from "./column-template/index.vue";
|
||||
import HeaderRenderer from "./header-renderer/index.vue";
|
||||
import Expand from "./expand.vue";
|
||||
import TreeTable from "./tree.vue";
|
||||
import TotalRow from "./totalRow.vue";
|
||||
import Merge from "./merge.vue";
|
||||
import CustomIndex from "./customIndex.vue";
|
||||
import Layout from "./layout.vue";
|
||||
import NestProp from "./nestProp.vue";
|
||||
import ImgPreview from "./imgPreview.vue";
|
||||
|
||||
export {
|
||||
Base,
|
||||
Stripe,
|
||||
Border,
|
||||
Status,
|
||||
FixHeader,
|
||||
FixColumn,
|
||||
FluidHeight,
|
||||
GroupHeader,
|
||||
Radio,
|
||||
MultipleChoice,
|
||||
Sortable,
|
||||
Filters,
|
||||
ColumnTemplate,
|
||||
HeaderRenderer,
|
||||
Expand,
|
||||
TreeTable,
|
||||
TotalRow,
|
||||
Merge,
|
||||
CustomIndex,
|
||||
Layout,
|
||||
NestProp,
|
||||
ImgPreview
|
||||
};
|
||||
56
src/views/pure-table/high.vue
Normal file
56
src/views/pure-table/high.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import { list } from "./high/list";
|
||||
import { Tabs, TabPane } from "@pureadmin/components";
|
||||
|
||||
defineOptions({
|
||||
name: "PureTableHigh"
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="font-medium">
|
||||
高级用法全部采用 tsx 语法,充分发挥
|
||||
<el-link
|
||||
href="https://github.com/xiaoxian521/pure-admin-table"
|
||||
target="_blank"
|
||||
style="font-size: 16px; margin: 0 4px 5px"
|
||||
>
|
||||
@pureadmin/table
|
||||
</el-link>
|
||||
的灵活性,维护整体表格只需操作 columns 配置即可
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-alert
|
||||
title="高级用法中所有表格都设置了 row-key ,后端需返回唯一值的字段,比如id 作用:1. 用来优化 Table
|
||||
的渲染,尤其当字段在深层结构中;2. 防止拖拽后表格组件内部混乱(拖拽必须设置哦,坑都帮您们踩过啦 ❤️)"
|
||||
type="info"
|
||||
:closable="false"
|
||||
/>
|
||||
|
||||
<Tabs :destroyInactiveTabPane="true">
|
||||
<TabPane v-for="item of list" :key="item.key">
|
||||
<template #tab>
|
||||
<el-tooltip :content="item.content" placement="top-end">
|
||||
<span>{{ item.title }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<component :is="item.component" />
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.ant-tabs-content-holder) {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
:deep(.el-alert__title) {
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
88
src/views/pure-table/high/data.ts
Normal file
88
src/views/pure-table/high/data.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import dayjs from "dayjs";
|
||||
import { clone } from "@pureadmin/utils";
|
||||
|
||||
const date = dayjs(new Date()).format("YYYY-MM-DD");
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date,
|
||||
name: "Tom",
|
||||
address: "No. 189, Grove St, Los Angeles"
|
||||
},
|
||||
{
|
||||
date,
|
||||
name: "Jack",
|
||||
address: "No. 189, Grove St, Los Angeles"
|
||||
},
|
||||
{
|
||||
date,
|
||||
name: "Dick",
|
||||
address: "No. 189, Grove St, Los Angeles"
|
||||
},
|
||||
{
|
||||
date,
|
||||
name: "Harry",
|
||||
address: "No. 189, Grove St, Los Angeles"
|
||||
},
|
||||
{
|
||||
date,
|
||||
name: "Sam",
|
||||
address: "No. 189, Grove St, Los Angeles"
|
||||
},
|
||||
{
|
||||
date,
|
||||
name: "Lucy",
|
||||
address: "No. 189, Grove St, Los Angeles"
|
||||
},
|
||||
{
|
||||
date,
|
||||
name: "Mary",
|
||||
address: "No. 189, Grove St, Los Angeles"
|
||||
},
|
||||
{
|
||||
date,
|
||||
name: "Mike",
|
||||
address: "No. 189, Grove St, Los Angeles"
|
||||
}
|
||||
];
|
||||
|
||||
const tableDataMore = clone(tableData, true).map(item =>
|
||||
Object.assign(item, {
|
||||
state: "California",
|
||||
city: "Los Angeles",
|
||||
"post-code": "CA 90036"
|
||||
})
|
||||
);
|
||||
|
||||
const tableDataImage = clone(tableData, true).map((item, index) =>
|
||||
Object.assign(item, {
|
||||
image: `https://xiaoxian521.github.io/pure-admin-table/imgs/${
|
||||
index + 1
|
||||
}.jpg`
|
||||
})
|
||||
);
|
||||
|
||||
const tableDataSortable = clone(tableData, true).map((item, index) =>
|
||||
Object.assign(item, {
|
||||
date: `${dayjs(new Date()).format("YYYY-MM")}-${index + 1}`
|
||||
})
|
||||
);
|
||||
|
||||
const tableDataDrag = clone(tableData, true).map((item, index) => {
|
||||
delete item["address"];
|
||||
return Object.assign(
|
||||
{
|
||||
id: index + 1,
|
||||
date: `${dayjs(new Date()).format("YYYY-MM")}-${index + 1}`
|
||||
},
|
||||
item
|
||||
);
|
||||
});
|
||||
|
||||
export {
|
||||
tableData,
|
||||
tableDataDrag,
|
||||
tableDataMore,
|
||||
tableDataImage,
|
||||
tableDataSortable
|
||||
};
|
||||
68
src/views/pure-table/high/drag/column/columns.tsx
Normal file
68
src/views/pure-table/high/drag/column/columns.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import Sortable from "sortablejs";
|
||||
import { tableDataDrag } from "../../data";
|
||||
import { ref, nextTick, onMounted } from "vue";
|
||||
|
||||
// 行拖拽演示
|
||||
export function useColumns() {
|
||||
const dataList = ref(tableDataDrag);
|
||||
|
||||
const columnsDrag = ref<TableColumnList>([
|
||||
{
|
||||
label: "ID",
|
||||
prop: "id"
|
||||
},
|
||||
{
|
||||
label: "日期",
|
||||
prop: "date"
|
||||
},
|
||||
{
|
||||
label: "姓名",
|
||||
prop: "name"
|
||||
}
|
||||
]);
|
||||
|
||||
const columns = ref<TableColumnList>([
|
||||
{
|
||||
label: "ID",
|
||||
prop: index => columnsDrag.value[index].prop as string
|
||||
},
|
||||
{
|
||||
label: "日期",
|
||||
prop: index => columnsDrag.value[index].prop as string
|
||||
},
|
||||
{
|
||||
label: "姓名",
|
||||
prop: index => columnsDrag.value[index].prop as string
|
||||
}
|
||||
]);
|
||||
|
||||
const columnDrop = (event: { preventDefault: () => void }) => {
|
||||
event.preventDefault();
|
||||
nextTick(() => {
|
||||
const wrapper: HTMLElement = document.querySelector(
|
||||
".el-table__header-wrapper tr"
|
||||
);
|
||||
Sortable.create(wrapper, {
|
||||
animation: 300,
|
||||
delay: 0,
|
||||
onEnd: ({ newIndex, oldIndex }) => {
|
||||
const oldItem = columnsDrag.value[oldIndex];
|
||||
columnsDrag.value.splice(oldIndex, 1);
|
||||
columnsDrag.value.splice(newIndex, 0, oldItem);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
columnDrop(event);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
columns,
|
||||
dataList,
|
||||
columnsDrag
|
||||
};
|
||||
}
|
||||
16
src/views/pure-table/high/drag/column/index.vue
Normal file
16
src/views/pure-table/high/drag/column/index.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { useColumns } from "./columns";
|
||||
|
||||
const { columns, dataList, columnsDrag } = useColumns();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex">
|
||||
<el-scrollbar height="700px">
|
||||
<code>
|
||||
<pre class="w-[700px]"> {{ columnsDrag }}</pre>
|
||||
</code>
|
||||
</el-scrollbar>
|
||||
<pure-table row-key="id" :data="dataList" :columns="columns" />
|
||||
</div>
|
||||
</template>
|
||||
69
src/views/pure-table/high/drag/row/columns.tsx
Normal file
69
src/views/pure-table/high/drag/row/columns.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import Sortable from "sortablejs";
|
||||
import { ref, nextTick } from "vue";
|
||||
import { tableDataDrag } from "../../data";
|
||||
|
||||
// 行拖拽演示
|
||||
export function useColumns() {
|
||||
const dataList = ref(tableDataDrag);
|
||||
|
||||
const rowDrop = (event: { preventDefault: () => void }) => {
|
||||
event.preventDefault();
|
||||
nextTick(() => {
|
||||
const wrapper: HTMLElement = document.querySelector(
|
||||
".el-table__body-wrapper tbody"
|
||||
);
|
||||
Sortable.create(wrapper, {
|
||||
animation: 300,
|
||||
handle: ".drag-btn",
|
||||
onEnd: ({ newIndex, oldIndex }) => {
|
||||
const currentRow = dataList.value.splice(oldIndex, 1)[0];
|
||||
dataList.value.splice(newIndex, 0, currentRow);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const columns: TableColumnList = [
|
||||
// {
|
||||
// width: 60,
|
||||
// cellRenderer: () => (
|
||||
// <iconify-icon-online
|
||||
// icon="icon-park-outline:drag"
|
||||
// class="drag-btn cursor-grab"
|
||||
// onMouseenter={(event: { preventDefault: () => void }) =>
|
||||
// rowDrop(event)
|
||||
// }
|
||||
// />
|
||||
// )
|
||||
// },
|
||||
{
|
||||
label: "ID",
|
||||
prop: "id",
|
||||
cellRenderer: ({ row }) => (
|
||||
<div class="flex items-center">
|
||||
<iconify-icon-online
|
||||
icon="icon-park-outline:drag"
|
||||
class="drag-btn cursor-grab"
|
||||
onMouseenter={(event: { preventDefault: () => void }) =>
|
||||
rowDrop(event)
|
||||
}
|
||||
/>
|
||||
<p class="ml-[16px]">{row.id}</p>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
label: "日期",
|
||||
prop: "date"
|
||||
},
|
||||
{
|
||||
label: "姓名",
|
||||
prop: "name"
|
||||
}
|
||||
];
|
||||
|
||||
return {
|
||||
columns,
|
||||
dataList
|
||||
};
|
||||
}
|
||||
16
src/views/pure-table/high/drag/row/index.vue
Normal file
16
src/views/pure-table/high/drag/row/index.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { useColumns } from "./columns";
|
||||
|
||||
const { columns, dataList } = useColumns();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex">
|
||||
<el-scrollbar height="700px">
|
||||
<code>
|
||||
<pre class="w-[700px]"> {{ dataList }}</pre>
|
||||
</code>
|
||||
</el-scrollbar>
|
||||
<pure-table row-key="id" :data="dataList" :columns="columns" />
|
||||
</div>
|
||||
</template>
|
||||
20
src/views/pure-table/high/list.tsx
Normal file
20
src/views/pure-table/high/list.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import RowDrag from "./drag/row/index.vue";
|
||||
import ColumnDrag from "./drag/column/index.vue";
|
||||
|
||||
const rendContent = (val: string) =>
|
||||
`代码位置:src/views/pure-table/high/${val}/index.vue`;
|
||||
|
||||
export const list = [
|
||||
{
|
||||
key: "rowDrag",
|
||||
content: rendContent("drag/row"),
|
||||
title: "拖拽表格(行拖拽)",
|
||||
component: RowDrag
|
||||
},
|
||||
{
|
||||
key: "columnDrag",
|
||||
content: rendContent("drag/column"),
|
||||
title: "拖拽表格(列拖拽)",
|
||||
component: ColumnDrag
|
||||
}
|
||||
];
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { list } from "./list";
|
||||
import { list } from "./base/list";
|
||||
import { Tabs, TabPane } from "@pureadmin/components";
|
||||
|
||||
defineOptions({
|
||||
@@ -26,6 +26,13 @@ defineOptions({
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-alert
|
||||
title="基础用法中大部分表格都没设置 row-key ,不过最好都设置一下,后端需返回唯一值的字段,比如id 作用:1. 用来优化 Table
|
||||
的渲染,尤其当字段在深层结构中;2. 防止某些操作导致表格组件内部混乱"
|
||||
type="info"
|
||||
:closable="false"
|
||||
/>
|
||||
|
||||
<Tabs :destroyInactiveTabPane="true">
|
||||
<TabPane v-for="item of list" :key="item.key">
|
||||
<template #tab>
|
||||
@@ -43,4 +50,8 @@ defineOptions({
|
||||
:deep(.ant-tabs-content-holder) {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
:deep(.el-alert__title) {
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user