最近公司项目经常用到一个拖拽 Sortable.js插件,所以有空的时候看了 Sortable.js 源码,总共1300多行这样,写的挺完美的。
拖拽的时候主要由这几个事件完成,
ondragstart 事件:当拖拽元素开始被拖拽的时候触发的事件,此事件作用在被拖曳元素上
ondragenter 事件:当拖曳元素进入目标元素的时候触发的事件,此事件作用在目标元素上
ondragover 事件:拖拽元素在目标元素上移动的时候触发的事件,此事件作用在目标元素上
ondrop 事件:被拖拽的元素在目标元素上同时鼠标放开触发的事件,此事件作用在目标元素上
ondragend 事件:当拖拽完成后触发的事件,此事件作用在被拖曳元素上
主要是拖拽的时候发生ondragstart事件和ondragover事件的时候节点交换位置,其实就是把他们的节点互相调换,当然这只是最简单的拖拽排序方式,里面用到了许多技术比用判断拖拽滚动条的时候是滚动拖拽元素上面的根节点的父节点滚动,还是滚动window上面的滚动条, 还有拖拽的时候利用getBoundingClientRect() 属性判断鼠标是在dom节点的左边,右边,上面,还是下面。还有利用回调和函数式编程声明函数,利用布尔值相加相减去,做0和1判断,利用了事件绑定来判定两个列表中的不同元素,这些都是很有趣的技术。
注意:这个插件是用html5 拖拽的所以也不支持ie9 以下浏览器
接下来我们先看看简单的简单的dome,先加载他的拖拽js Sortable.js 插件,和app.css. 创建一个简单的拖拽很简单 只要传递一个dom节点进去就可以,第二个参数传一个空对象进去
当然app.css,加不加无所谓,如果不加的话要加一个样式就是
.sortable-ghost { opacity: 0.4; background-color: #F4E2C9; }
拖拽的时候有阴影效果更好看些
<!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> </head> <link href="https://www.jb51.net/app.css" type="text/css"/> <script src="https://www.jb51.net/Sortable.js"></script> <body> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> </ul> <script> Sortable.create(document.getElementById('foo'), {}); </script> </body> </html>
该插件还提供了拖拽时候动画,让拖拽变得更炫,很简单加多一个参数就行animation: 150,拖拽时间内执行完动画的时间。里面是用css3动画的ie9以下浏览器 含ie9浏览器不支持
<!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> </head> <link href="https://www.jb51.net/app.css" type="text/css"/> <script src="https://www.jb51.net/Sortable.js"></script> <body> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> </ul> <script> Sortable.create(document.getElementById('foo'), { animation: 150, //动画参数 }); </script> </body> </html>
这个插件不仅仅提供拖拽功能,还提供了拖拽完之后排序,当然排序的思维很简单,判断鼠标按下去拖拽的那个节点和拖拽到目标节点的两个元素发生ondragover的时候判断他们的dom节点位置,并且互换dom位置就形成了排序。拖拽完成只有 Sortable.js 插件还提供了几个事件接口,我们看看那dome,
<!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> </head> <link href="https://www.jb51.net/app.css" type="text/css"/> <script src="https://www.jb51.net/Sortable.js"></script> <body> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> </ul> <script> Sortable.create(document.getElementById('foo'), { animation: 150, //动画参数 onAdd: function (evt){ //拖拽时候添加有新的节点的时候发生该事件 console.log('onAdd.foo:', [evt.item, evt.from]); }, onUpdate: function (evt){ //拖拽更新节点位置发生该事件 console.log('onUpdate.foo:', [evt.item, evt.from]); }, onRemove: function (evt){ //删除拖拽节点的时候促发该事件 console.log('onRemove.foo:', [evt.item, evt.from]); }, onStart:function(evt){ //开始拖拽出发该函数 console.log('onStart.foo:', [evt.item, evt.from]); }, onSort:function(evt){ //发生排序发生该事件 console.log('onSort.foo:', [evt.item, evt.from]); }, onEnd: function(evt){ //拖拽完毕之后发生该事件 console.log('onEnd.foo:', [evt.item, evt.from]); } }); </script> </body> </html>
我们看看上面的例子,首先看看当拖拽完成的时候他发生事件顺序