I G U P
web爱好者
Copyright©2018 by igup

拖拽排序的实现

<!DOCTYPE html>
<html lang=”en”>

<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
<title>拖动排序</title>
<style>
body {
margin: 0;
padding: 0;
}

.box {
display: flex;
font-size: 15px;
}

.items {
margin: 20px 30px;
position: relative;
background-color: #f6f9fa;
overflow: hidden;
border-radius: 4px;
}

.item {
width: 100px;
height: 48px;
line-height: 48px;
text-align: center;
transition: background-color .3s, color .3s, box-shadow .5s;
cursor: pointer;
user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
}

.item:hover {
background-color: #00a1d6;
color: #fff;
}

.select {
position: absolute;
background-color: #00a1d6;
color: #fff;
box-shadow: 0 4px 4px #ccc;
z-index: 999;
}

.hold {
cursor: inherit;
border: 1px dashed #ccc;
box-sizing: border-box;
/*animation: hold-higther 2000ms ease-in;*/
}

@keyframes hold-higther {
0% {
transform: scale(.4);
}
100% {
transform: scale(1);
}
}
</style>
</head>

<body>
<div class=”box”></div>
<script>
const $ = selectors => document.querySelector(selectors);
const $$ = selectors => document.querySelectorAll(selectors);
const navList = [‘小强’, ‘小明’, ‘小红’, ‘小绿’, ‘小白’, ‘小紫’, ‘小强’, ‘小明’, ‘小红’, ‘小绿’, ‘小白’, ‘小紫’];

/*1: 创建一个div class为items,将这个div放入box类中
* 2: 为数组中每个数创建一个div, class类为:item 将值存入div
* 3: 将数组中的每个数存入items这个dom中
* 4: 为每个div自定义dataset属性: data-sortindex , 值为他们的排序
* dom结构为:
* <div class=’box’>
<div class=’items’>
<div class=’item’ data-sortindex=0>小强</div>



</div>
</div>
*/
const holdItemDom = document.createElement(‘div’);
holdItemDom.classList.add(‘item’, ‘hold’);
const listDom = document.createElement(‘div’);
listDom.classList.add(‘items’);
navList.forEach((v, i, arr) => {
const itemDom = document.createElement(‘div’);
itemDom.classList.add(‘item’);
// 为每个div自定义dataset属性: data-sortindex , 值为他们的排序
itemDom.dataset.sortindex = i;
itemDom.textContent = v;
listDom.appendChild(itemDom);
});

$(‘.box’).appendChild(listDom);

//主要代码
var dragObj;
//考虑到item数量会很多,不需要给每个item单独绑定mousedown,mousemove,mouseup事件
//为class为 items, 这个div 添加一个 鼠标按下事件
listDom.onmousedown = (event) => {
let currenIndex, previousIndex;

// 选择item下面的所有的item
const itemDomList = $$(‘.items .item’);

// 获取数据的长度
const listLength = navList.length;

//定义一个变量储存当前这个dom距离顶部的距离
const startY = event.clientY;

//找到mousedown的item
let selectIndex;

//event.target 表示你当前点击的这个dom对象, 存入变量 dragObj 中
dragObj = event.target;
console.log(event);
console.log(dragObj);
console.log(Array.from(itemDomList).length);
Array.from(itemDomList).forEach((v, i) => {
if (v === event.target) {
//让selectIndex 这个变量储存当前点击的这个dom的下标
selectIndex = i;
}
});

//在当前按住的dom后面插入一个空的class=hold的dom用来占位,避免因拖动时, 因位置缺失而上下闪动
dragObj.after(holdItemDom);

//在按住的这个dom上添加一个class :select, 并且设置为绝对定位 (父节点为相对定位,将dom的移动控制在当前父dom中)
dragObj.classList.add(‘select’);

// 并且将按住的这个dom 的 top设置为:当前这个dom距离顶部的高度
dragObj.style.top = dragObj.clientHeight * selectIndex + ‘px’;

// 定义一个变量 用来储存当前dom的高度
const itemHeight = dragObj.clientHeight;

//再定义一个变量储存当前按下这个dom的下标
let topIndex = selectIndex;

console.log(‘topIndex:’ + topIndex);

//定义一个变量用来储存当前这个dom绝对定位的距离顶部的高度
const startTop = dragObj.style.top;

console.log(‘startTop:’+startTop);

//定义一个变量来储存当前dom前面有几个变量
previousIndex = Math.ceil((parseInt(startTop) – itemHeight / 2) / itemHeight);

console.log(‘previousIndex:’+previousIndex);

//鼠标点击后的拖动事件
document.onmousemove = function (event) {
//为拖动的这个dom添加一个class: select
dragObj.classList.add(‘select’);
//定义一个变量,储存拖动的这个dom距离顶部的距离
const moveY = event.clientY;
console.log(‘moveY :’ + moveY);
//定义一个变量储存 = 按住时候的元素距离顶部的 + 拖动的距离 = 距离顶部的实际高度
const presentTop = parseInt(startTop) + (moveY – startY);
//让按住的这个元素定位到拖动的位置(实际拖动的高度)
dragObj.style.top = presentTop + ‘px’;
// 定义一个变量储存计算当前拖动的dom前面应该在是第几个dom
currenIndex = Math.ceil((presentTop – itemHeight / 2) / itemHeight);
console.log(‘currenIndex:’+currenIndex)
//当这个值小于0的时候,让这个值等于0
if (currenIndex < 0) currenIndex = 0;
//当这个值大于总dom的(下标)长度时, 让其等于最后一个dom的下标
if (currenIndex > listLength – 1) currenIndex = listLength – 1;
//当按住不懂时拖动的时候前面dom的个数 与 拖动以后前面的dom的数量不相等的时候,删除在后面插入的dom
if (previousIndex !== currenIndex) {
holdItemDom.remove();
//当向上拖动的时候( 按住时候前面的dom , 与拖动之后前面的dom数量,以及下标的对比 )
if (previousIndex > currenIndex && currenIndex < topIndex) {
// 删除拖动的这个dom
dragObj.remove();
// 在拖动到的位置前面加上拖动的dom
itemDomList[currenIndex].before(dragObj);
// 并在前面加上一个空的class=hold的dom
dragObj.after(holdItemDom);
} else {
// 当向下拖动的时候
const currentItems = $$(‘.box .item’);
//在拖动到的位置的前面增加一个空的class=hold的dom
currentItems[currenIndex].after(holdItemDom);
}
// 当所有判断执行完以后( 也就是拖动的尾声 ),将拖动后的值赋值给previousIndex 来储存(拖动的时候,时时刻刻更改在dom数组里面的位置)
previousIndex = currenIndex;
// 当按住值得下标 大于 拖动后的下标, 将拖动后的下标赋值给 topIndex来储存(拖动的时候,时时刻刻更改在dom数组里面的位置)
if (currenIndex < topIndex) topIndex = currenIndex;
}
};
// 当鼠标释放的时候
document.onmouseup = function (event) {
const currentItems = $$(‘.box .item’);
if (currenIndex > topIndex) {
currentItems[currenIndex].after(dragObj);
}
holdItemDom.remove();
dragObj.classList.remove(‘select’);
dragObj.removeAttribute(‘style’);
document.onmousemove = null;
document.onmouseup = null;
}
};
</script>
</body>

</html>

2018-09-29
文章归档:

说点什么

  Subscribe  
提醒