根据dom元素位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
li {
list-style: none;
}
.drag-wrap {
position: relative;
width: 300px;
}
.drag-wrap .drag-item {
transition: unset;
z-index: 2;
}
.drag-wrap li {
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.15);
position: absolute;
width: 180px;
/* margin: 10px; */
height: 90px;
user-select: none;
background-color: blueviolet;
transition: left 0.3s ease-in-out,
top 0.3s ease-in-out;
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div id="drag-wrap" style="margin: 200px;">
<ul class="drag-wrap" id="drag-wrap-top">
<li>
<h1>1</h1>
<p>888888</p>
</li>
<li>
<h1>2</h1>
<p>888888</p>
</li>
<li>
<h1>3</h1>
<p>888888</p>
</li>
<li>
<h1>4</h1>
<p>888888</p>
</li>
<li>
<h1>5</h1>
<p>888888</p>
</li>
<li>
<h1>6</h1>
<p>888888</p>
</li>
</ul>
<p style="height: 50px;">——————————————</p>
<ul class="drag-wrap" id="drag-wrap-bottom">
<li>
<h1>1</h1>
<p>------</p>
</li>
<li>
<h1>2</h1>
<p>------</p>
</li>
<li>
<h1>3</h1>
<p>------</p>
</li>
<li>
<h1>4</h1>
<p>------</p>
</li>
<li>
<h1>5</h1>
<p>------</p>
</li>
<li>
<h1>6</h1>
<p>------</p>
</li>
<li>
<h1>7</h1>
<p>------</p>
</li>
<li>
<h1>8</h1>
<p>------</p>
</li>
<li>
<h1>9</h1>
<p>------</p>
</li>
<li>
<h1>10</h1>
<p>------</p>
</li>
<li>
<h1>11</h1>
<p>------</p>
</li>
<li>
<h1>12</h1>
<p>------</p>
</li>
</ul>
</div>
<script>
var dragObj = {
setGroupHeight() {
this.el.style.height = this.nodeHeight * Math.ceil(this.nodeList.length / this.nodeNumber) + 'px'
this.enterEl.style.height = this.nodeHeight * Math.ceil(this.enternodeList.length / this.nodeNumber) + 'px'
},
/**
* 给每个节点进行一次排序
* @param {Array} 元素节点数组
*/
sortNodePosition(nodeList) {
nodeList.forEach(node => {
node.style.left = node.sort % this.nodeNumber * this.nodeWidth + 'px';
node.style.top = Math.floor(node.sort / this.nodeNumber) * this.nodeHeight + 'px';
})
},
/**
* 获取父标签
*/
getParentNode(node, tagName = 'LI') {
let liNode = null;
function getLiNode(node) {
if (node.tagName.toUpperCase() === 'HTML') {
liNode = null;
}
else if (node.tagName.toUpperCase() === tagName) {
liNode = node;
} else {
getLiNode(node.parentNode)
}
}
getLiNode(node)
return liNode;
},
el: null,
enterEl: null,
// 节点宽度
nodeWidth: 200,
// 节点高度
nodeHeight: 100,
// 每行节点个数
nodeNumber: 3,
// 容器下所有卡片的节点
nodeList: [],
enternodeList: [],
init() {
this.el = document.getElementById('drag-wrap-top');
this.enterEl = document.getElementById('drag-wrap-bottom');
this.nodeList = [...this.el.children];
this.nodeList.forEach((node, index) => {
node.setAttribute('draggable', true)
node.sort = index;
});
this.sortNodePosition(this.nodeList)
this.enternodeList = [...this.enterEl.children];
this.enternodeList.forEach((node, index) => {
node.setAttribute('draggable', true)
node.sort = index;
});
this.sortNodePosition(this.enternodeList)
this.el.addEventListener('dragstart', (e) => {
this.target = this.getParentNode(e.target);
this.target.classList.add('drag-item')
})
this.el.addEventListener('dragenter', (e) => {
let toTarget = this.getParentNode(e.target);
// 拖到li上面,排除自己上面
if (toTarget && toTarget !== this.target) {
// 不同的父标签(ul)
if (toTarget.parentNode.id !== this.target.parentNode.id) {
toTarget.parentNode.appendChild(this.target);
this.removeNodeSort(this.target.sort, this.enternodeList);
this.appendNodeSort(this.target, toTarget.sort, this.nodeList)
this.setGroupHeight();
}
// 相同的父标签(ul)
else {
this.changeNodeSort(toTarget.sort, this.nodeList);
}
}
// 如果直接拖动ul空白处
else if (e.target.id === this.el.id && this.target.parentNode.id !== e.target.id) {
e.target.appendChild(this.target);
this.removeNodeSort(this.target.sort, this.enternodeList);
this.appendNodeSort(this.target, this.nodeList.length, this.nodeList)
this.setGroupHeight();
}
})
this.el.addEventListener('dragend', (e) => {
this.target.classList.remove('drag-item')
})
this.enterEl.addEventListener('dragstart', (e) => {
this.target = this.getParentNode(e.target);
this.target.classList.add('drag-item')
})
this.enterEl.addEventListener('dragenter', (e) => {
let toTarget = this.getParentNode(e.target);
// 拖到li上面,排除自己上面
if (toTarget && toTarget !== this.target) {
// 不同的父标签(ul)
if (toTarget.parentNode.id !== this.target.parentNode.id) {
toTarget.parentNode.appendChild(this.target);
this.removeNodeSort(this.target.sort, this.nodeList);
this.appendNodeSort(this.target, toTarget.sort, this.enternodeList)
this.setGroupHeight();
}
// 相同的父标签(ul)
else {
this.changeNodeSort(toTarget.sort, this.enternodeList);
}
}
// 如果直接拖动ul空白处
else if (e.target.id === this.enterEl.id && this.target.parentNode.id !== e.target.id) {
e.target.appendChild(this.target);
this.removeNodeSort(this.target.sort, this.nodeList);
this.appendNodeSort(this.target, this.enternodeList.length, this.enternodeList)
this.setGroupHeight();
}
})
this.enterEl.addEventListener('dragend', (e) => {
this.target.classList.remove('drag-item')
})
this.setGroupHeight();
},
removeNodeSort(oldSort, nodeList) {
let nodeIndex = nodeList.findIndex(node => node.sort === oldSort);
nodeList.splice(nodeIndex, 1)
nodeList.forEach((node, index) => {
if (node.sort > oldSort) node.sort--;
})
// 把除了当前节点的,所有节点都重新排序下位置
this.sortNodePosition(nodeList);
},
appendNodeSort(dragNode, newSort, nodeList) {
nodeList.forEach(node => {
if (node.sort >= newSort) node.sort++;
})
// 给当前节点排序重新赋值,不要漏了这个
nodeList.push(dragNode);
dragNode.sort = newSort
// 把除了当前节点的,所有节点都重新排序下位置
this.sortNodePosition(nodeList);
},
/**
* 计算出需要排序变化的节点,改变节点sort属性
*/
changeNodeSort(newSort, nodeList) {
// 在移动过程中,当前节点sort没有改变,不需要重复计算排序。
var oldSort = this.target.sort;
if (newSort !== oldSort) {
nodeList.forEach(node => {
// 往前移动,老位置 - 新位置(包含)之间的所有节点,排序都加1
if (newSort < oldSort) {
if (node.sort >= newSort && node.sort < oldSort) node.sort++;
}
// 往后移动,老位置 - 新位置(包含)之间的所有节点,排序都减1
else {
if (node.sort <= newSort && node.sort > oldSort) node.sort--;
}
})
// 给当前节点排序重新赋值,不要漏了这个
this.target.sort = newSort
// 把除了当前节点的,所有节点都重新排序下位置
this.sortNodePosition(nodeList);
}
},
}
dragObj.init();
</script>
</body>
</html>
根据鼠标位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>拖拽排序</title>
<style>
* {
padding: 0;
margin: 0;
}
li {
list-style: none;
}
.drag-wrap {
position: relative;
width: 500px;
}
.drag-wrap .drag-item {
transition: unset;
z-index: 2;
}
.drag-wrap li {
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.15);
position: absolute;
width: 90px;
margin: 5px;
height: 60px;
user-select: none;
background-color: blueviolet;
transition: left 0.3s ease-in-out,
top 0.3s ease-in-out;
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div id="drag-wrap" style="margin: 200px;">
<ul class="drag-wrap" id="drag-wrap-top">
<li>
<h1>1</h1>
<p>888888</p>
</li>
<li>
<h1>2</h1>
<p>888888</p>
</li>
<li>
<h1>3</h1>
<p>888888</p>
</li>
<li>
<h1>4</h1>
<p>888888</p>
</li>
<li>
<h1>5</h1>
<p>888888</p>
</li>
<li>
<h1>6</h1>
<p>888888</p>
</li>
<li>
<h1>7</h1>
<p>888888</p>
</li>
<li>
<h1>8</h1>
<p>888888</p>
</li>
<li>
<h1>9</h1>
<p>888888</p>
</li>
<li>
<h1>10</h1>
<p>888888</p>
</li>
<li>
<h1>11</h1>
<p>888888</p>
</li>
<li>
<h1>12</h1>
<p>888888</p>
</li>
</ul>
<p draggable="true" style="height: 100px;">123</p>
<ul class="drag-wrap" id="drag-wrap-bottom">
<li>
<h1>1</h1>
<p>------</p>
</li>
<li>
<h1>2</h1>
<p>------</p>
</li>
<li>
<h1>3</h1>
<p>------</p>
</li>
<li>
<h1>4</h1>
<p>------</p>
</li>
<li>
<h1>5</h1>
<p>------</p>
</li>
<li>
<h1>6</h1>
<p>------</p>
</li>
<li>
<h1>7</h1>
<p>------</p>
</li>
<!-- <li>
<h1>8</h1>
<p>------</p>
</li>
<li>
<h1>9</h1>
<p>------</p>
</li>
<li>
<h1>10</h1>
<p>------</p>
</li>
<li>
<h1>11</h1>
<p>------</p>
</li>
<li>
<h1>12</h1>
<p>------</p>
</li> -->
</ul>
</div>
<script>
var bian = false
function dragSort() {
return {
// 容器元素
el: null,
enterEl: null,
// 节点宽度
nodeWidth: 100,
// 节点高度
nodeHeight: 70,
// 每行节点个数
nodeNumber: 5,
// 容器下所有卡片的节点
nodeList: [],
// 记录拖拽中,被拖拽节点的序号;防止重复排序
index: 0,
/**
* 获取父标签
*/
getParentNode(node, tagName = 'LI') {
let liNode = null;
function getLiNode(node) {
if (node.tagName.toUpperCase() === 'HTML') {
liNode = null;
}
else if (node.tagName.toUpperCase() === tagName) {
liNode = node;
} else {
getLiNode(node.parentNode)
}
}
getLiNode(node)
return liNode;
},
/**
* 给每个节点进行一次排序
* @param {Array} 元素节点数组
*/
sortNodePosition(nodeList) {
nodeList.forEach(node => {
node.style.left = node.sort % this.nodeNumber * this.nodeWidth + 'px';
node.style.top = Math.floor(node.sort / this.nodeNumber) * this.nodeHeight + 'px';
})
},
getChild() {
// 获取容器下所有卡片的节点
this.nodeList = [...this.el.children];
this.el.style.height = this.nodeHeight * Math.ceil(this.nodeList.length / this.nodeNumber) + 'px'
// 给所有节点初始化序号,绑定事件
this.nodeList.forEach((node, index) => {
node.setAttribute('draggable', true)
node.sort = index;
});
this.enternodeList = [...this.enterEl.children];
this.enterEl.style.height = this.nodeHeight * Math.ceil(this.enternodeList.length / this.nodeNumber) + 'px'
// 给所有节点初始化序号,绑定事件
this.enternodeList.forEach((node, index) => {
node.setAttribute('draggable', true)
node.sort = index;
});
},
init(el, enterEl) {
this.el = el;
this.enterEl = enterEl;
document.getElementById('drag-wrap').addEventListener('dragstart', this.addDragEvent.bind(this));
this.getChild()
// 进行第一次排序
this.sortNodePosition(this.nodeList);
this.sortNodePosition(this.enternodeList);
this.el.addEventListener('dragover', (e) => {
if (this.el.id !== this.target.parentNode.id) {
let rect = this.el.getBoundingClientRect()
let xNumer = Math.round((e.clientX - rect.left) / this.nodeWidth) - 1;
this.styleLeft = xNumer * this.nodeWidth;
this.styleTop = 0;
this.startLeft = this.styleLeft + this.relativeX + rect.left;
this.startTop = rect.top + this.relativeY;
bian = 'drag-wrap-top'
this.el.appendChild(this.target);
}
}, true)
this.enterEl.addEventListener('dragover', (e) => {
console.log('-----------------')
if (this.enterEl.id !== this.target.parentNode.id) {
let rect = this.enterEl.getBoundingClientRect()
let xNumer = Math.round((e.clientX - rect.left) / this.nodeWidth) - 1;
this.styleLeft = xNumer * this.nodeWidth;
this.styleTop = 0;
// console.log(xNumer, '------')
this.startLeft = this.styleLeft + this.relativeX + rect.left;
this.startTop = rect.top + this.relativeY;
console.log(this.startTop)
bian = 'drag-wrap-bottom'
this.enterEl.insertBefore(this.target, this.enterEl.firstChild);
}
}, true)
},
/**
* 绑定拖拽事件
* @param {Object} e 事件对象
*/
addDragEvent(e) {
// 当前拖拽的节点
let { target } = e;
this.target = target = this.getParentNode(target);
// 增加class,取消动效,防止拖拽掩饰;增加zIndex层级
target.className = 'drag-item';
this.styleLeft = parseInt(target.style.left);
this.styleTop = parseInt(target.style.top);
this.startLeft = e.clientX;
this.startTop = e.clientY;
// 鼠标按下坐标,相对于target元素 左上角的位置差
this.relativeX = e.clientX - target.getBoundingClientRect().x;
this.relativeY = e.clientY - target.getBoundingClientRect().y;
console.log(this.relativeX, this.relativeY)
// 拖动节点
const mousemoveFn = (moveEvent) => {
// console.log(this.startLeft)
let endLeft = this.styleLeft + (moveEvent.clientX - this.startLeft),
endTop = this.styleTop + (moveEvent.clientY - this.startTop);
if (bian === 'drag-wrap-top') {
this.removeNodeSort(this.target.sort, this.enternodeList)
this.appendNodeSort(this.target, endLeft, endTop, this.nodeList);
} else if (bian === 'drag-wrap-bottom') {
this.removeNodeSort(this.target.sort, this.nodeList)
this.appendNodeSort(this.target, endLeft, endTop, this.enternodeList);
}
this.changeNodeSort(target, endLeft, endTop, target.parentNode.id === 'drag-wrap-top' ? this.nodeList:this.enternodeList);
bian = '';
}
document.getElementById('drag-wrap').addEventListener('dragover', mousemoveFn);
// 释放拖动的节点
const mouseupFn = () => {
// 因为移动的时候要保证移动位置,不能对当前节点排序,所有鼠标释放,进行下排序
// this.sortNodePosition([target]);
setTimeout(() => { target.removeAttribute('class') });
// 这步可以不做,为了和谷歌一样,把dom也进行排序
this.sortDom(this.el, this.nodeList);
this.sortDom(this.enterEl, this.enternodeList);
document.getElementById('drag-wrap').removeEventListener('dragover', mousemoveFn);
document.getElementById('drag-wrap').removeEventListener('dragend', mouseupFn);
}
document.getElementById('drag-wrap').addEventListener('dragend', mouseupFn);
},
/**
* 计算出需要排序变化的节点,改变节点sort属性
*/
changeNodeSort(dragNode, x, y, nodeList) {
// 元素移动:水平方向超过 nodeWidth 一半,算sort+1;垂直方向超过 nodeHeight 一半,算进入到下一排(sort + nodeNumber)
var newSort = Math.max(Math.round(y / this.nodeHeight), 0) * this.nodeNumber + Math.round(x / this.nodeWidth);
newSort = newSort > nodeList.length - 1 ? nodeList.length - 1 : newSort;
newSort = newSort < 0 ? 0 : newSort;
// 在移动过程中,当前节点sort没有改变,不需要重复计算排序。
if (newSort !== this.index) {
this.index = newSort;
var oldSort = dragNode.sort;
nodeList.forEach(node => {
// 往前移动,老位置 - 新位置(包含)之间的所有节点,排序都加1
if (newSort < oldSort) {
if (node.sort >= newSort && node.sort < oldSort) node.sort++;
}
// 往后移动,老位置 - 新位置(包含)之间的所有节点,排序都减1
else {
if (node.sort <= newSort && node.sort > oldSort) node.sort--;
}
})
// 给当前节点排序重新赋值,不要漏了这个
dragNode.sort = newSort
// 把除了当前节点的,所有节点都重新排序下位置
this.sortNodePosition(nodeList);
}
},
removeNodeSort(oldSort, nodeList) {
console.log(oldSort)
let nodeIndex = nodeList.findIndex(node => node.sort === oldSort);
// console.log(nodeIndex)
nodeList.splice(nodeIndex, 1)
nodeList.forEach((node,index) => {
if (node.sort > oldSort) node.sort--;
})
// 把除了当前节点的,所有节点都重新排序下位置
this.sortNodePosition(nodeList);
},
appendNodeSort(dragNode, x, y, nodeList) {
nodeList.push(dragNode);
// 元素移动:水平方向超过 nodeWidth 一半,算sort+1;垂直方向超过 nodeHeight 一半,算进入到下一排(sort + nodeNumber)
var newSort = Math.max(Math.round(y / this.nodeHeight), 0) * this.nodeNumber + Math.round(x / this.nodeWidth);
newSort = newSort > nodeList.length - 1 ? nodeList.length - 1 : newSort;
newSort = newSort < 0 ? 0 : newSort;
console.log(newSort, 'newSort')
// 给当前节点排序重新赋值,不要漏了这个
dragNode.sort = newSort
nodeList.forEach(node => {
if (node.sort >= newSort) node.sort++;
})
// 把除了当前节点的,所有节点都重新排序下位置
this.sortNodePosition(nodeList);
},
/**
* 对DOM排序
*/
sortDom(dom, nodeList) {
let newSortWrap = document.createDocumentFragment();
nodeList = [...dom.children].sort((a, b) => a.sort - b.sort);
nodeList.forEach(node => {
newSortWrap.appendChild(node);
});
dom.appendChild(newSortWrap);
},
}
}
dragSort().init(document.querySelector('#drag-wrap-top'), document.querySelector('#drag-wrap-bottom'));
// dragSort().init(document.querySelector('#drag-wrap-bottom'), document.querySelector('#drag-wrap-top'));
</script>
</body>
</html>