最近在项目中遇到了拖动排序的需求,所以就学习了一下H5的新属性,写篇博客记录一下。

draggable属性是指定当前元素可以被拖动的属性;我们要为需要拖动的元素设置该属性
<div id="columns">
  <div class="column" draggable="true"><header>A</header></div>
  <div class="column" draggable="true"><header>B</header></div>
  <div class="column" draggable="true"><header>C</header></div>
</div>
<style>
/* Prevent the text contents of draggable elements from being selectable. */
[draggable] {
  -moz-user-select: none;
  -khtml-user-select: none;
  -webkit-user-select: none;
  user-select: none;
  /* Required to make elements draggable in old WebKit */
  -khtml-user-drag: element;
  -webkit-user-drag: element;
}
.column {
  height: 150px;
  width: 150px;
  float: left;
  border: 2px solid #666666;
  background-color: #ccc;
  margin-right: 5px;
  -webkit-border-radius: 10px;
  -ms-border-radius: 10px;
  -moz-border-radius: 10px;
  border-radius: 10px;
  -webkit-box-shadow: inset 0 0 3px #000;
  -ms-box-shadow: inset 0 0 3px #000;
  box-shadow: inset 0 0 3px #000;
  text-align: center;
  cursor: move;
}
.column header {
  color: #fff;
  text-shadow: #000 0 1px;
  box-shadow: 5px;
  padding: 5px;
  background: -moz-linear-gradient(left center, rgb(0,0,0), rgb(79,79,79), rgb(21,21,21));
  background: -webkit-gradient(linear, left top, right top,
                               color-stop(0, rgb(0,0,0)),
                               color-stop(0.50, rgb(79,79,79)),
                               color-stop(1, rgb(21,21,21)));
  background: -webkit-linear-gradient(left center, rgb(0,0,0), rgb(79,79,79), rgb(21,21,21));
  background: -ms-linear-gradient(left center, rgb(0,0,0), rgb(79,79,79), rgb(21,21,21));
  border-bottom: 1px solid #ddd;
  -webkit-border-top-left-radius: 10px;
  -moz-border-radius-topleft: 10px;
  -ms-border-radius-topleft: 10px;
  border-top-left-radius: 10px;
  -webkit-border-top-right-radius: 10px;
  -ms-border-top-right-radius: 10px;
  -moz-border-radius-topright: 10px;
  border-top-right-radius: 10px;
}

.ghost{
  optcity:0.6;
}

</style>

监听拖动事件

  • dragstart   //当用户开始拖动一个元素或者一个选择文本的时候 dragstart 事件就会触发。
  • drag      //当元素或者选择的文本被拖动时触发 drag 事件 (每几百毫秒)
  • dragenter   //当拖动的元素或被选择的文本进入有效的放置目标时, dragenter 事件被触发。
  • dragleave   //当一个被拖动的元素或者被选择的文本离开一个有效的拖放目标时,将会触发dragleave 事件
  • dragover    //当元素或者选择的文本被拖拽到一个有效的放置目标上时,触发 dragover 事件(每几百毫秒触发一次)。
  • drop       //当一个元素或是选中的文字被拖拽释放到一个有效的释放目标位置时,drop 事件被抛出。
  • dragend    //拖放事件在拖放操作结束时触发(通过释放鼠标按钮或单击escape键)

我们需要以下概念:源元素(拖动的起源点)、数据有效负载(我们尝试拖放的内容)和目标(接纳拖放内容的区域)。源元素可以是图片、列表、链接、文件对象、HTML 内容等。目标是接纳用户尝试放置的数据的放置区(或放置区组)。请注意,并非所有元素都可以作为目标(例如图片)。

dataTransfer

dataTransfer是用于元素拖动时控制拖动的类型和数据交换的,主要有以下属性:

  •   dragEffect             获取 / 设置实际的放置效果,它应该始终设置成 effectAllowed  的可能值之一;拖动时鼠标显示的效果,根据自己的功能来设定 
    • copy: 复制到新的位置
    • move: 移动到新的位置.
    • link: 建立一个源位置到新位置的链接.
    • none: 禁止放置(禁止任何操作).
  •   effectAllowed        用来指定拖动时被允许的效果
  • 可能的值:

    • copy: 复制到新的位置.
    • move:移动到新的位置 .
    • link:建立一个源位置到新位置的链接.
    • copyLink: 允许复制或者链接.
    • copyMove: 允许复制或者移动.
    • linkMove: 允许链接或者移动.
    • all: 允许所有的操作.
    • none: 禁止所有操作.
    • uninitialized: 缺省值(默认值), 相当于 all.
  •   files                       包含一个在数据传输上所有可用的本地文件列表

方法:

  • clearData()          删除与给定类型关联的数据。类型参数是可选的。如果类型为空或未指定,将删除所有类型相关联的数据。如果不存在指定类型的数据,或数据传输不包含任何数据,此方法将没有任何效果。
  • obj.clearData(type);
  • getData()             根据指定的类型检索数据,如果指定类型的数据不存在或者该 DataTransfer 对象中没有数据,方法将返回一个空字符串。
  • obj.getData(type);
  • setData()             为一个给定的类型设置数据。如果该数据类型不存在,它将添加到的末尾,这样类型列表中的最后一个项目将是新的格式。如果已经存在的数据类型,替换相同的位置的现有数据。就是,当更换相同类型的数据时,不会更改类型列表的顺序。
  • obj.setData(type,data);
  • setDragImage()   自定义一个期望的拖动时的图片。大多数情况下,这项不用设置,因为被拖动的节点被创建成默认图片。
  • obj.setDragImage(imgElement,offsetX,offsetY);    offsetX,offsetY为图片与鼠标的偏移量
function sortable(rootEl, onUpdate) {
    var dragEl;
    
    // 将所有的子类元素设置为可拖动的  draggable = true
    [].slice.call(rootEl.children).forEach(function (itemEl) {
        itemEl.draggable = true;
    });
    
    // 该函数负责进行排序
    function _onDragOver(evt) {
        evt.preventDefault();
        evt.dataTransfer.dropEffect = 'move';
       
        var target = evt.target;
        if (target && target !== dragEl && target.nodeName == 'LI') {
            // Sorting
            rootEl.insertBefore(dragEl, target.nextSibling || target);
        }
    }
    
    // 排序结束后的钩子函数
    function _onDragEnd(evt){
        evt.preventDefault();
       
        dragEl.classList.remove('ghost');
        rootEl.removeEventListener('dragover', _onDragOver, false);
        rootEl.removeEventListener('dragend', _onDragEnd, false);

        onUpdate(dragEl);
    }
    
    // 开始排序  监听父元素的dragstart 事件
    rootEl.addEventListener('dragstart', function (evt){
        // 保存当前被拖动的子元素
        dragEl = evt.target; 
        
        // 设置移动的类型
        evt.dataTransfer.effectAllowed = 'move';
        // 设置要移动的数据
        evt.dataTransfer.setData('Text', dragEl.textContent);
        // 监听元素的dragover dragend 事件
        rootEl.addEventListener('dragover', _onDragOver, false);
        rootEl.addEventListener('dragend', _onDragEnd, false);
 
        //这里如果不添加setTimeout拖出去的元素也会添加上该类名  
        setTimeout(function () {
            dragEl.classList.add('ghost');
        }, 0)
    }, false);
 }
                        
 // Using                    
 sortable(document.getElementById('columns'), function (item) {
    console.log(item);
 });

 参考文章:1.Sorting with the help of HTML5 Drag'n'Drop API

                   2.Native HTML5 Drag and Drop