在做后台管理系统的时候,经常需要表格里面的每行排序,自定义可拖拽表格,更改样式方便。
一、实现效果
进行拖拽演示:
可拖拽排序表格
无滚动条样式:
有滚动条样式:
二、代码
使用react+scss+ts,实现页面。
在pages文件夹下新建一个文件夹 tablePage 。然后在tablePage 下面新建两个文件,index.tsx , index.scss 。
index.tsx
import './index.scss';
import { useState, useEffect } from "react";
function FileTest() {
// 表格body的滚动条
const [scrollWidth, setScrollWidth] = useState(0)
//挂载后,计算表格body是否有滚动条,从而改变宽度(页面高度变化,以及表格展示内容条数变化,都需要调用此方法)
function changeWidth() {
var myElement: any = document.getElementById('myElement');
var widthWithBorder = myElement.offsetWidth;
var widthWithoutBorder = myElement.clientWidth;
setScrollWidth(widthWithBorder - widthWithoutBorder);
}
useEffect(() => {
changeWidth();
}, []);
//表格标题,和宽度占父元素百分比,(采用百分比的方式,是因为需要进行电脑大小屏适配,这样可以确保表格充满屏幕),字符串为空的地方是间隔。
let tableTitle = [
['', 2],
['序号', 5],
['姓名', 12],
['', 1],
['部门', 12],
['', 1],
['组织', 30],
['', 1],
['时间', 10],
['', 1],
['状态', 10],
['', 1],
['操作', 14]
]
//------------------------------------------------- 拖拽 ----------------------------------------------------------------/
const [dragging, setDragging] = useState(null)
function dragStart(e: any) {
e.stopPropagation();
setDragging(e.target); // 保存被拖动的行
}
// 判断是兄还是弟
function getSort(draggingElement: any, targetElement: any, tbody: any) {
var siblings = [];
let number = tbody.children.length
for (var i = 0; i < number; i++) {
siblings.push(tbody.children[i]);
}
// 正在拖拽的
var index = siblings.indexOf(draggingElement);
// 当前悬浮的
var targetIndex = siblings.indexOf(targetElement);
if (targetIndex > -1) {
if (index === targetIndex) {
return false;
} else {
if (targetIndex === number.length - 1) {
// 此时在最后插入元素
return null;
} else if (index < targetIndex) {
return siblings[targetIndex + 1] || null;
} else if (index > targetIndex) {
return siblings[targetIndex] || null;
}
}
}
return null;
}
function onDropEvent(e: any) {
e.preventDefault();
e.stopPropagation();
var table: any = document.getElementById('sortable-table');
var tbody = table.getElementsByTagName('tbody')[0];
if (dragging) {
var afterElement = getSort(dragging, e.target, tbody);
if (e.target && e.target.tagName === "TR") {
e.target.style.border = '';
e.target.style.borderBottom = '1px solid #F2F5F4';
if (afterElement !== false) {
if (afterElement === null) {
tbody.appendChild(dragging);
} else {
tbody.insertBefore(dragging, afterElement);
}
}
}
}
}
function onDragOverEvent(e: any) {
e.preventDefault(); // 阻止默认行为
if (e.target.tagName === "TR") {
e.target.style.border = '1px solid #1BCEB2';
}
}
function ondragLeave(e: any) {
// 清除拖拽区域样式
if (e.target.tagName === "TR") {
e.target.style.border = '';
e.target.style.borderBottom = '1px solid #F2F5F4';
}
}
return (
<div className='omm-edu-Manage-box-set'>
{/* 左侧和上侧,留有导航栏位置 ,如不需要,直接将top和left设置为0即可*/}
<div className="omm-edu-Manage-content-set">
{/* 表格 */}
<div className="omm-table-father-set">
<table border={0} className='omm-table-box-set' id="sortable-table">
<thead>
<tr className='omm-table-title-box-set'>
{tableTitle.map((item, index) => (
<th key={index} className='omm-table-title-set' style={{ width: `${item[1]}%` }}>
{item[0]}</th>
))}
</tr>
</thead>
<tbody className='omm-table-content-box-all-set' id="myElement" style={{ width: `calc(100% + ${scrollWidth}px)` }} onDrop={(e) => { onDropEvent(e) }} onDragOver={(e) => { onDragOverEvent(e) }} onDragLeave={(e) => { ondragLeave(e) }}>
{[1, 2, 3, 4, 5, 6, 7].map((item, indexA) => (
<tr key={indexA} className='omm-table-content-box-set' draggable="true" onDragStart={(e) => { dragStart(e) }}>
{tableTitle.map((item, index) => (
<td key={index} className='omm-table-content-set' style={{ width: `${item[1]}%` }}>
{index === 1 ? indexA
: item[0]
}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
);
}
export default FileTest;
index.scss
table {
border-collapse: collapse;
}
.omm-edu-Manage-box-set {
width: 100%;
height: 100%;
background-color: #F7FAF8;
.omm-edu-Manage-content-set {
position: absolute;
top: 72px;
left: 216px;
right: 20px;
bottom: 12px;
background-color: #fff;
border-radius: 12px;
min-width: 1000px;
min-height: 500px;
padding: 16px;
.omm-table-father-set {
position: absolute;
top: 16px;
left: 16px;
right: 16px;
bottom: 79px;
.omm-table-box-set {
width: 100%;
.omm-table-title-box-set {
height: 42px !important;
max-height: 42px !important;
background: #F2F5F4;
width: 100%;
position: relative;
z-index: 1;
.omm-table-title-set {
height: 42px !important;
max-height: 42px !important;
color: #505553;
font-size: 14px;
font-weight: normal;
text-align: left;
}
}
.omm-table-content-box-all-set {
overflow-y: auto;
position: absolute;
top: 42px;
left: 0;
right: 0;
bottom: 0;
.omm-table-content-box-set {
min-height: 44px !important;
border-bottom: 1px solid #F2F5F4;
position: relative;
width: 100%;
word-wrap: break-word;
font-size: 14px;
padding: 5px 0;
box-sizing: border-box;
display: flex;
align-items: center;
&:hover {
background: #F7FAF8;
cursor: pointer;
}
.omm-table-content-set {
display: inline-block;
vertical-align: middle;
height: 100%;
color: #1E201F;
font-size: 14px;
font-weight: normal;
pointer-events: none;
}
}
}
}
}
}
}
现在在当前页面使用,后期会提取为公共组件,使用更方便,也让拖拽样式有更多选择。