前言css
本文的内容就如题所述,之因此写这么个东西是有缘由的,由于这两天重作公司的一个功能发现里面须要一个拖拽排序的功能.之前都是使用jquery各类插件去搞,由于这个项目不限制浏览器兼容问题就打算用HTML5来弄,走在时代的前沿不是,后来发现一个个属性那么写有点麻烦,就搜到一个HTML5的排序插件(纯粹抱着试试看的内心...不解释),没想到尼玛这插件居然要jquery1.7以上支持,并且尼玛仍是jquery~他妹的,不带你玩了,本身写~html
正文jquery
对HTML5有过了解的童鞋必定会知道它能够说很是使用的一个新特性,就是出现了元素拖放的接口,具体的API想详细了解的建议直接w3school去了解.
浏览器
(1) 经过draggable属性使你的元素可拖拽.
dom
这里我会对用到东西一点点的作出声明以及解释,铺垫的差很少了开始上干货,先构建一下基础的html和css,由于本文主旨不是样式因此没搞得太美观,就是OSC的绿以及中国红为主色,别介意:
this
<!doctype html> <html> <head> <meta charset="UTF-8"> <title>HTML5-Drag-Demo by 顽Shi</title> <style> .column { height: 200px; width: 200px; float: left; border: 2px solid black; background-color: green; margin-right: 5px; text-align: center; cursor: move; } .column header { color: black; text-shadow: #000 0 1px; box-shadow: 5px; padding: 5px; background: red; border-bottom: 1px solid black; } </style> </head> <body> <div id="columns"> <div draggable="true"><header>div1</header></div> <div draggable="true"><header>div2</header></div> <div draggable="true"><header>div3</header></div> </div> </body> </html>
这就是html部分的代码,咱们会逐渐完善它,效果图以下:
spa
html和css代码很简单我就不解释了,有疑问的请留言的说...这里咱们只是为div加上了一个draggable的属性,而且将属性值设为true.这就是HTML5新增的一个属性,将一个元素设置为可拖拽.其实若是你们细心会发现浏览器上看到的不少内容都是可拖拽的,好比连接或者图片,我举一个百度首页的例子截图给你们,能够看到我拖拽百度logo也是能够的,并且它的代码上也没有draggables属性.
插件
这就是纯粹的浏览器支持,默认状况下大多数浏览器对于带有href属性的内容,好比超连接和图片等都是支持拖拽的,可是这个拖拽和咱们今天要讲的DOM拖拽是不同的.回到咱们的demo,此时div1,div2,div3均可以进行拖拽了,相似与复制了一个本身的感受,若是松开鼠标还会有一个滑回原来位置的默认动做.截图以下:
code
拖拽动做在大多数浏览器下会建立一个自身的副本留在原来位置,这是一个很重要的东西,咱们接下来会用到.
htm
(2) 对拖拽的动做进行监听
如今元素能够移动了,可是距离咱们的目标还有必定的差距,咱们想作的是什么?
咱们但愿的效果是元素被拖起来以后,能够在达到指定区域后,经过松开鼠标的动做将它固定在一个咱们指定的位置上.因此咱们要对这个过程当中涉及到的动做加以监控.(不是全部的区域都能指定为元素被固定的区域,好比说图片就能接收其余元素).
在拖动开始后咱们但愿被拖动的元素能变得透明一些,以区分出拖动和未拖动的不一样,监听ondrugstart能够轻松实现,代码以下:
<script> var columns = document.querySelectorAll('#columns .column'); [].forEach.call(columns,function(column){ column.addEventListener("dragstart",domdrugstart,false); }); function domdrugstart(e) { e.target.style.opacity = '0.5'; } </script>
此时拖动一个元素,它的透明度会变为50%.不过拖动结束后这一效果还保留着,因此要在拖动结束重置会100%.这个留到最后实现便可.
接下来咱们实现的一个效果,是要在拖拽时将其可能放置的位置标识出来,显示出哪里是可能放置的位置,尤为在鼠标悬停或者划过的时候.这一过程须要ondragenter,ondragover以及ondragleave这三个事件的监听.代码以下:
.column.over { border: 3px dashed #000; } //将这个样式添加到style中 <script> var columns = document.querySelectorAll('#columns .column'); [].forEach.call(columns,function(column){ column.addEventListener("dragstart",domdrugstart,false); column.addEventListener('dragenter', domdrugenter, false); column.addEventListener('dragover', domdrugover, false); column.addEventListener('dragleave', domdrugleave, false); }); function domdrugstart(e) { e.target.style.opacity = '0.5'; } function domdrugenter(e) { e.target.classList.add('over'); } function domdrugover(e) { if (e.preventDefault) { e.preventDefault(); } e.dataTransfer.dropEffect = 'move'; return false; } function domdrugleave(e) { e.target.classList.remove('over'); } </script>
解释一下代码,dragenter事件的动做是拖动后鼠标进入另外一个可接受区域,此时给添加了监听的对象加上一个虚线的边框,之因此使用dragenter而不是dragover是由于前者只在进入区域时触发一次,后者会反复触发.dragover则是为了阻止一些相似超连接拖动跳转的默认动做,dragleave则是去掉当拖拽鼠标划出区域时,去掉虚线.
(3) 添加释放动做
到此为止元素已经能够进行拖拽,而且而且在拖拽的过程有虚线的提示.可是如今还缺乏一个完成的动做,也就是拖拽结束的动做,这个动做要有两个做用,一是和over相似去阻止浏览器的默认动做,二是根据咱们的需求进行DOM操做.
这里用到drop以及dragend:
<script> var columns = document.querySelectorAll('#columns .column'); [].forEach.call(columns,function(column){ column.addEventListener("dragstart",domdrugstart,false); column.addEventListener('dragenter', domdrugenter, false); column.addEventListener('dragover', domdrugover, false); column.addEventListener('dragleave', domdrugleave, false); column.addEventListener('drop', domdrop, false); column.addEventListener('dragend', domdrapend, false); }); function domdrugstart(e) { e.target.style.opacity = '0.5'; } function domdrugenter(e) { e.target.classList.add('over'); } function domdrugover(e) { if (e.preventDefault) { e.preventDefault(); } e.dataTransfer.dropEffect = 'move'; return false; } function domdrugleave(e) { e.target.classList.remove('over'); } function domdrop(e) { if (e.stopPropagation) { e.stopPropagation(); } return false; } function domdrapend(e) { [].forEach.call(columns, function (column) { column.classList.remove('over'); column.style.opacity = '1'; }); } </script>
至此咱们会发现,尚未完成元素的交换这一动做,只是让全部的元素看起来可拖拽了而已,由于还缺乏最后的DataTransfer对象.这是一个很神奇的东西,它使拖动的过程当中能够发送数据,能够在dragstart中设置而且在drop或者dragend时读取.
这里咱们先看添加的代码:
var dragEl = null; function domdrugstart(e) { e.target.style.opacity = '0.5'; dragEl = this; e.dataTransfer.effectAllowed = "move"; e.dataTransfer.setData("text/html",this.innerHTML); } function domdrop(e) { if (e.stopPropagation) { e.stopPropagation(); } if (dragEl != this) { dragEl.innerHTML = this.innerHTML; this.innerHTML = e.dataTransfer.getData('text/html'); } return false; }
效果如图:
最后这段代码可能你们会有疑惑,解释一下.首先定义了一个全局变量dragEl它的做用就是用来存储被拖拽元素的html,而后在释放拖拽时和释放区域的元素进行交换.e.dataTransfer.effectAllowed这个是用来限制元素的,它限制了元素的拖动类型为move.紧接着经过代码将被拖动元素的html进行setData.而后这里set的值能够经过get进行获取.
基本上到这就完成了整个功能,稍微进行一下封装就能够造成插件,这个有兴趣的能够本身搞~最后附源码:
<!doctype html> <html> <head> <meta charset="UTF-8"> <title>HTML5-Drag-Demo by 顽Shi</title> <style> .column { height: 200px; width: 200px; float: left; border: 1px solid black; background-color: green; margin-right: 5px; text-align: center; cursor: move; } .column header { color: black; text-shadow: #000 0 1px; box-shadow: 5px; padding: 5px; background: red; border-bottom: 1px solid black; } .column.over { border: 3px dashed #000; } </style> </head> <body> <div id="columns"> <div class="column" draggable="true"><header>div1</header></div> <div class="column" draggable="true"><header>div2</header></div> <div class="column" draggable="true"><header>div3</header></div> </div> </body> <script> var columns = document.querySelectorAll('#columns .column'); var dragEl = null; [].forEach.call(columns,function(column){ column.addEventListener("dragstart",domdrugstart,false); column.addEventListener('dragenter', domdrugenter, false); column.addEventListener('dragover', domdrugover, false); column.addEventListener('dragleave', domdrugleave, false); column.addEventListener('drop', domdrop, false); column.addEventListener('dragend', domdrapend, false); }); function domdrugstart(e) { e.target.style.opacity = '0.5'; dragEl = this; e.dataTransfer.effectAllowed = "move"; e.dataTransfer.setData("text/html",this.innerHTML); } function domdrugenter(e) { e.target.classList.add('over'); } function domdrugover(e) { if (e.preventDefault) { e.preventDefault(); } e.dataTransfer.dropEffect = 'move'; return false; } function domdrugleave(e) { e.target.classList.remove('over'); } function domdrop(e) { if (e.stopPropagation) { e.stopPropagation(); } if (dragEl != this) { dragEl.innerHTML = this.innerHTML; this.innerHTML = e.dataTransfer.getData('text/html'); } return false; } function domdrapend(e) { [].forEach.call(columns, function (column) { column.classList.remove('over'); column.style.opacity = '1'; }); } </script> </html>