今天应一个朋友的委托,研究一下拖拽排序,我记得我上次写拖拽排序,由于方法太死板,效果我一直不是很满意,一直想再从写一个,一直没机会(懒),此次由于公司部门变更因此有了一些时间(无聊)来写,原本准备使用Vue写,奈何功夫不到家在自定义指令的时候,问题卡住了,研究了一段时间以后,仍是决定放弃,研究一下Vue再来写过,因此本次仍是用了Jquery来写。css
直接上代码html
这是CSS部分数组
1 *{/*Css*/
2 margin: 0px;
3 padding: 0px;
4 list-style: none;
5 text-decoration: none;
6 border: none;
7 color: #000;
8 text-shadow: none;
9 box-shadow: none;
10 outline: none 11 }
12 button, ul {
13 margin-left: 20px;
14 }
15 ul li{
16 background: #AAABCA;
17 margin: 3px 0px;
18 width: 200px;
19 overflow: hidden;
20 }
21 ul li span{
22 float: right;
23 padding: 0px 3px;
24 }
25 ul li.on{
26 height: 50px;
27 }
28 ul li span:hover{
29 background: #ccc;
30 cursor: pointer;
31 }
32 button{
33 padding: 10px;
34 cursor: pointer;
35 }
HTML部分 app
1 <button id="add">add</button>
2 <ul class="list">
3 <li>item1 4 <span class="remo">X</span>
5 <span class="goUp">^</span>
6 <span class="goDown">V</span>
7 </li>
8 </ul>
Js部分dom
1 $(function(){ 2 //---------
3 Array.prototype.min = function() { 4 var min = this[0]; 5 var index = 0; 6 var len = this.length; 7 for (var i = 1; i < len; i++){ 8 if (this[i] < min){ 9 min = this[i]; 10 } 11 } 12 return min; 13 } 14 //---------
15 var i = $('.list').find('li').length; 16 var cls = 'on'; 17 $('#add').click(function(){ 18 i++; 19 cls = cls?false:'on'; 20 $('.list').append('<li class="'+cls+'">item'+i+' <span class="remo">X</span><span class="goUp">^</span><span class="goDown">V</span></li>'); 21 addmous(); 22
23 }); 24 addmous(); 25 var keyf = true;//变量控制第一次拖拽结束前,不容许其余操做
26 function addmous(){ 27 $('.remo').off('mousedown').on('mousedown',function(){//绑定删除元素
28 keyf = false; 29 $(this).parent().remove(); 30 }); 31 $('.goUp').off('mousedown mouseup').on({'mousedown':function(){//向上按钮
32 keyf = false; 33 return false; 34 },'mouseup':function(){ 35 let $this = $(this).parent(); 36 let prev = $this.prev(); 37 $this.after(prev); 38 keyf = true; 39 }}); 40 $('.goDown').off('mousedown mouseup').on({'mousedown':function(){//向下按钮
41 keyf = false; 42 },'mouseup':function(){ 43 let $this = $(this).parent(); 44 let prev = $this.next(); 45 $this.before(prev); 46 keyf = true; 47 return false; 48 }}); 49 $('.list li').off('mousedown').on({'mousedown':moused,'mouseover':function(){ 50 return false; 51 }});//绑定mousedown事件
52 var scrollLength = null; 53 function moused(ev){ //mousedown
54 if(keyf == false){return};//若是以前还有未完成的操做,那么return
55 keyf = false; 56 scrollLength = $(window).scrollTop() - 20;//保持滚动以后,不会错位,为了优化显示效果,减去20
57 var allTop = []; 58 var allLi = $('.list').find('li'); 59 for(var i = 0 ; i < allLi.length ; i++){//拿到ul当中全部li距离顶部的距离
60 allTop.push(allLi.eq(i).offset().top); 61 } 62 var _this = $(this); 63 var l = $(this).offset().left; 64 var t = $(this).offset().top - 3; 65 let mX = ev.clientX, 66 mY = ev.clientY + scrollLength, 67 disX = mX - l, //肯定鼠标按下的位置
68 disY = mY - t; 69 $(this).css({'position': 'absolute','left':l +'px','top':t +'px'});//将点击元素从不一样文档流中的元素,变成定位元素
70 var html = $(this).html();//拿到当前元素的 内容和class,复制成影子
71 var aCls = $(this).attr('class'); 72 $(this).after('<li class="addLi '+aCls+'" style="opacity:.4">'+html+'</li>'); 73 $(document).on({'mousemove':mousem,'mouseup':mouseu}); 74 //将move,up事件,绑定在document身上,防止快速拖拽容易丢失的问题
75 function mousem(ev){ //mousemove
76 keyf = false; 77 var setArr = []; 78 scrollLength = $(window).scrollTop() - 20; //解决滚动条问题
79 let mX = ev.clientX, 80 mY = ev.clientY + scrollLength,//鼠标距离加上滚动的距离,防止滚动以后错位
81 l = mX - disX; 82 t = mY - disY; 83 _this.css({'left':l+'px','top':t+'px'})//修改left,top造成拖拽
84 for(var i = 0 ;i < allTop.length ; i++){//循环以前拿到的全部Li的top数组
85 var zo = mY - allTop[i]; //使用鼠标的top,减去全部的li的top,(也就是鼠标到全部li的距离)
86 setArr.push(zo < 0?zo*-1:zo); //全部距离转化成正数
87 } 88 var arrMin = setArr.min();//拿到鼠标到全部li的距离中的最小数(离鼠标最近li)
89 var minIndex = setArr.indexOf(arrMin,0);//查找距离鼠标最近的li的下标
90 var allLi2 = $('.list').find('li'); 91 if(minIndex == 0){//若是距离鼠标最近的是第一个
92 mY < allLi2.eq(0).offset().top ? allLi2.eq(0).before($('.addLi')):allLi2.eq(0).after($('.addLi')); 93 //再判断鼠标的的位置在不在第一个元素的上面,在上面,就往li[0]的前面插入,不然在后面插入
94 }else if (minIndex == allTop.length -1){ 95 //最后一个元素,和第一个道理同样,写法相反
96 mY > allLi2.eq(allTop.length).offset().top ? allLi2.eq(allTop.length).after($('.addLi')):allLi2.eq(allTop.length).before($('.addLi')); 97 }else{ 98 //中间元素
99 allLi2.eq(minIndex).after($('.addLi'));//将影子插入到 距离鼠标最近li的后面
100 } 101 } 102 function mouseu(){ //mouseup
103 var ol = $('.addLi').offset().left;//拿到影子元素的坐标
104 var ot = $('.addLi').offset().top; 105 $(document).off({'mousemove':mousem,'mouseup':mouseu});//将拖拽元素的left,top变化到影子的目标坐标上
106 _this.animate({'left':ol,'top':ot - 3},function(){//减3,是为了优化视觉效果
107 _this.css('position','static');//取消定位
108 $('.addLi').after(_this);//将目标元素插入到影子元素后面
109 $('.addLi').remove();//删除影子元素
110 keyf = true;//结束动做
111 }) 112 } 113 return false
114 } 115
116 } 117
118 })
嗯,其中的原理,我认为在注释当中写的比较详细了,自己难度没有特别高,主要的思路就是:先把多个Li的offsetTop存成数组allTop,而后使用鼠标的Top值,减去allTop的每一项,生成新的数组setArr,setArr就是全部Li距离鼠标的距离,找到其中最小的值,就是距离鼠标最近的,而后找到最小值得在数组中的下标,也就是对应的dom元素Li在的下标,找到最近的Li以后,插入影子元素便可,主要在onmousemove,中的判断影子元素位置的地方,对数组的操做,须要注意的还有,当产生滚动条的时候,须要吧滚动距离给加上,不然会错位。优化
不说了,我得去找工做了,加油!this
以上spa
2017-04-26 击鼓卖糖prototype