今天應一個朋友的委託,研究一下拖拽排序,我記得我上次寫拖拽排序,由於方法太死板,效果我一直不是很滿意,一直想再從寫一個,一直沒機會(懶),此次由於公司部門變更因此有了一些時間(無聊)來寫,原本準備使用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