这个需求出来本可以使用很多插件,但由于后面的需求无法满足在固定插件下继续开发,所以参考了layuitable插件制作了这样一个简单的行列拖拽排序。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.3/css/bootstrap.min.css" rel="stylesheet">
<style>
.Reports {
width: calc(100% - 20%);
margin: 20px 10% !important;
text-align: center;
position: relative;
}
body,
#sortable tbody {
position: relative;
}
#sortable thead th p {
margin: 0;
}
#sortable thead th {
vertical-align: middle;
height: 50px;
border: 1px solid #dee2e6
}
#sortable tbody tr td:first-child {
cursor: move;
background-color: #555555;
width: 150px;
}
#sortable th:first-child {
width: 150px;
background-color: #555555;
border-right: 1px solid #555;
border-top: 1px solid #555;
border-bottom: 1px solid #555;
position: relative;
}
#sortable tbody td {
vertical-align: middle;
position: relative;
}
#sortable tbody tr {
position: inherit;
border: 1px solid black;
}
#sortable .vis_hide {
visibility: hidden;
/* left: -2px; */
border: none;
border-bottom: 1px solid #e4e4e4;
}
.createDivBg {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 10000;
cursor: move;
-moz-user-select: none;
-webkit-user-select: none;
-o-user-select: none;
-ms-user-select: none
}
.createDiv {
border: 1px dotted #ccc;
height: 34px;
line-height: 34px;
background: #eee;
position: fixed;
z-index: 100000
}
body {
-webkit-touch-callout: none;
/* iOS Safari */
-webkit-user-select: none;
/* Chrome/Safari/Opera */
-khtml-user-select: none;
/* Konqueror */
-moz-user-select: none;
/* Firefox */
-ms-user-select: none;
/* Internet Explorer/Edge */
user-select: none;
/* Non-prefixed version, currently */
}
</style>
</head>
<body>
<div style="">
<div class="Reports">
<table id="sortable" class="table table-bordered">
<thead id="sorthead">
<tr>
<th class="Thead">
<p>全不选</p>
<p>全选</p>
</th>
<th data-key="1">样式一</th>
<th data-key="2">样式二</th>
<th data-key="3">样式三</th>
<th class="Thead">总价</th>
</tr>
</thead>
<tbody>
<tr id="div1" data-index="0">
<td class="RowSort Thead">小海豚</td>
<td data-key="1">
<div>
<p>产品一</p>
<p>¥500</p>
</div>
</td>
<td data-key="2">
<div>
<p>产品二</p>
<p>¥500</p>
</div>
</td>
<td data-key="3">
<div>
<p>产品三</p>
<p>¥560</p>
</div>
</td>
<td>¥400</td>
</tr>
<tr id="div2" data-index="1">
<td class="RowSort Thead">美的</td>
<td data-key="1">
<div>
<p>产品一</p>
<p>¥200</p>
</div>
</td>
<td data-key="2">
<div>
<p>产品二</p>
<p>¥500</p>
</div>
</td>
<td data-key="3">
<div>
<p>产品三</p>
<p>¥500</p>
</div>
</td>
<td>¥400</td>
</tr>
<tr id="div3" data-index="2">
<td class="RowSort Thead">志高</td>
<td data-key="1">
<div>
<p>产品一</p>
<p>¥500</p>
</div>
</td>
<td data-key="2">
<div>
<p>产品二</p>
<p>¥5900</p>
</div>
</td>
<td data-key="3">
<div>
<p>产品三</p>
<p>¥500</p>
</div>
</td>
<td>¥400</td>
</tbody>
</table>
</div>
</div>
<script>
var _this = this,
tableId = $("#sortable"),
isDragging = false;
window.onload = function() {
$("table tbody tr").each(function() {
let $sel = $(this).children("td:first");
rowDrag($sel)
})
coldrag()
}
//列拖动
function coldrag() {
// 绑定鼠标按下事件
$("table thead").find('th:not(:first)').css('cursor', 'move')
.on('mousedown', function(e) {
// 非鼠标左键都不执行
if (e.button !== 0) {
return;
}
e.preventDefault();
var $this = $(this),
field = $this.text(),
key = $this.data('key'),
headWidth = this.offsetWidth,
thLeft = this.offsetLeft,
trwidth = $this.parent().width(),
headHight = this.offsetHeight;
if (!key) {
return;
}
var $cloneHead = $this.clone().addClass("vis_hide").css({
'width': headWidth,
'border': 'none',
'border-bottom': '1px solid #e4e4e4'
}).attr("isclone", ''),
originLeft = $this.position().left,
originTop = $this.offset().top,
disX = e.clientX - originLeft, // 鼠标距离被移动元素左侧的距离
color = $this.parents('tr:eq(0)').css("background-color"),
width = $this.width(),
moveDistince = 0,
$that = $(this),
firstmove = true,
isStart = true;
// 移动事件
$('body').on('mousemove', function(e) {
if (isStart && $cloneHead) {
if (!isDragging) {
$this.after($cloneHead);
$this.css({
'position': 'absolute',
'z-index': 1,
'border': '1px solid #e4e4e4',
'background-color': '#e4e4e4',
'width': headWidth,
'height': headHight,
'top': 0
});
}
}
if (firstmove) {
$("table tbody").find('td[data-key="' + key + '"]').each(function() {
$(this).after($(this).clone().addClass("vis_hide").css({
'border': '1px solid #e4e4e4',
'border-left': 'none'
}).attr('data-clone', ''));
$(this).css({
'position': 'absolute',
'z-index': 1,
'background-color': '#e4e4e4',
'width': headWidth,
'top': '-2px'
});
})
}
firstmove = false
isDragging = true;
var left = e.clientX - disX, // 计算当前被移动列左侧位置应该哪里
$leftTh = $cloneHead.prev().prev(),
hasLeftTh = $leftTh.length > 0,
leftKey = hasLeftTh ? $leftTh.data('key') : [],
$rightTh = $cloneHead.next(),
hasRightTh = $rightTh.length > 0,
rightKey = hasRightTh ? $rightTh.data('key') : [],
leftMove = hasLeftTh && ($cloneHead.position().left - left > $leftTh.width() / 2.0), //左移超过要进过的元素的一半就返回true
rightMove = hasRightTh && (left - $cloneHead.position().left > $rightTh.width() / 2.0),
moveDistince = Math.abs($cloneHead.position().left - left); //记录移动距离
$this.css('left', left + 2); //要移动的元素
// Thead 是要固定不能超过的类,
if (leftMove) {
if (!$leftTh.hasClass("Thead")) $cloneHead.after($leftTh);
} else if (rightMove) {
if (!$rightTh.hasClass("Thead")) $cloneHead.prev().before($rightTh);
}
//这里是td的交换
$("table tbody").find('td[data-key="' + key + '"][data-clone]').each(function() {
$(this).prev().css('left', left);
if (leftMove) {
if (!$leftTh.hasClass("Thead")) {
if ($(this).prev().prev().length !== 0) {
$(this).after($(this).prev().prev());
}
}
} else if (rightMove) {
if (!$rightTh.hasClass("Thead")) {
if ($(this).next().length !== 0) {
$(this).prev().before($(this).next());
}
}
}
})
}).on('mouseup', function() {
$('body').off('mousemove').off('mouseup')
if (isStart && $cloneHead) {
isStart = false;
if (isDragging) {
isDragging = false;
$this.css({
'position': 'relative',
'z-index': 'inherit',
'width': headWidth,
'height': 'auto',
'left': 'inherit',
'background-color': 'transparent'
});
// 样式回滚到不影响
$this.parent().find('th[data-key="' + key + '"][isclone]').remove(); //移除克隆项
var prefKey = $this.prev().data('key');
$('table tbody').find('td[data-key="' + key + '"][data-clone]').each(function() {
$(this).prev().removeClass('vis_hide').css({
'position': 'relative',
'z-index': 'inherit',
'left': 'inherit',
'width': headWidth,
'top': 0,
'background-color': 'transparent'
});
$(this).remove();
});
$cloneHead = null;
} else {
$that.unbind('click');
}
}
})
})
}
//行拖动
function rowDrag($sel) {
// 被暂停 或者 不是鼠标左键 则取消拖拽效果
$sel.on("mousedown", function(e) {
// if (_this.suspendConfig[tableId].rowDrag || e.button !== 0) {
// return;
// }
var $this = $(this),
index = parseInt($this.parent().data('index')),
$bodyTr = $("table").children('tbody').children('tr[data-index=' + index + ']'),
$cloneTr = $bodyTr.clone().css('visibility', 'hidden'),
bodyScrollTop = $("table").children('tbody').scrollTop(), // 记录当前滚动条位置
originTop = $this.parent().position().top,
disY = e.clientY - originTop, // 鼠标距离被移动元素上侧的距离(点的位置不同,数值不同)
disW = this.parentNode.offsetWidth;
$('body').on("mousemove", function(e) {
if (!isDragging) {
isDragging = true;
// $(this).css({
// cursor:'move'
// })
$bodyTr.after($cloneTr);
$bodyTr.css({
'position': 'absolute',
'z-index': 1,
'width': disW,
'background-color': '#e4e4e4'
})
$bodyTr.children("td").css({
"display": 'inline-block',
'width': 100 / $bodyTr.children("td").length - 1 + '%',
'white-space': 'nowrap',
'border': 'none',
'text-algin': 'center'
})
}
var top = e.clientY - disY + ($("table").children('tbody').scrollTop() - bodyScrollTop), // 计算当前被移动行top位置应该哪里
trTop = $cloneTr.position().top, //当前行所在位置
$UpTr = $bodyTr.prev(),
hasUpTr = $UpTr.length > 0,
$downTr = $cloneTr.next(),
hasDownTr = $downTr.length > 0,
upMove = hasUpTr && (trTop - top > $UpTr.height() / 2.0),
downMove = hasDownTr && (top - trTop > $downTr.height() / 2.0);
if (trTop - top > 0 ? !hasUpTr : !hasDownTr) {
$bodyTr.css('top', trTop);
return;
}
$bodyTr.css('top', top);
if (upMove) {
updateDataIndex($bodyTr, -1)
$cloneTr.after(updateDataIndex($UpTr, 1));
} else if (downMove) {
updateDataIndex($bodyTr, 1).before(updateDataIndex($downTr, -1))
}
// 同步 data-index
function updateDataIndex($el, diff) {
var tempIndex = parseInt($el.data('index')) + diff;
$el.data('index', tempIndex);
$el.attr('data-index', tempIndex);
return $el
}
}).on('mouseup', function(e) {
$('body').off('mousemove').off('mouseup');
if (isDragging) {
isDragging = false;
$bodyTr.css({
'position': 'inherit',
'z-index': 'inherit',
'top': 0,
'width': 'auto',
'background-color': 'transparent'
});
$bodyTr.children("td").css({
"display": 'table-cell',
'width': 'auto',
border: '1px solid #dee2e6',
'text-algin': 'center'
})
$bodyTr.next().remove();
}
})
})
}
</script>
</body>
</html>