html5 drag and drop [1]

原来拖拽(drag and drop 或者 dnd)只能使用mousedown,mouseup等鼠标事件来模拟实现,html5提供了drag and drop相关事件来处理拖拽。
这里讲html5的拖拽实现。dnd的w3c文档在此:http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dnd

属性

标签属性:draggable draggable=”true” 表示元素可被拖动。
CSS属性:cursor设为move,这样鼠标经过元素时交互上显示为可拖动。

事件

  • dragstart
  • drag
  • dragenter
  • dragleave
  • dragover
  • drop
  • dragend

1.dragstart,dragenter,dragleave,dragover事件

下面实现的是拖动时透明度设为40%。

  • A
  • B
  • C

注意:
1.当拖动链接等有默认事件的元素时,要在dragover事件中用e.preventDefault()阻止默认事件。否则drop事件不会触发。
如果是从其他应用软件或是文件中拖东西进来,尤其是图片的时候,默认的动作是显示这个图片或是相关信息,并不是真的执行drop。此时需要用用document的ondragover事件把它直接干掉。
2.css设置user-select:none;防止拖动时元素内部文字被选中。
3.为什么在dragenter而不是dragover里设置css属性:
如果用dragover,那么该事件会被持续触发到元素离开,这对性能会有很大影响,如果用dragenter那么只会触发一次。
试试加上注释掉的两行,看console,你就知道用dragover对页面性能会有多大影响了。

[draggable] {
  -moz-user-select: none;
  -khtml-user-select: none;
  -webkit-user-select: none;
  user-select: none;
}
<script>
 function handleDragStart(e) {
  this.style.opacity = '0.4';  // this / e.target is the source node.
}
function handleDragOver(e) {
  if (e.preventDefault) {
    e.preventDefault(); // Necessary. Allows us to drop.
  }
  e.dataTransfer.dropEffect = 'move';  // See the section on the DataTransfer object.
  return false;
}
function handleDragEnter(e) {
  // this / e.target is the current hover target.
  this.classList.add('over');
}
function handleDragLeave(e) {
  this.classList.remove('over');  // this / e.target is previous target element.
}
var cols = document.querySelectorAll('.demo-box li');
[].forEach.call(cols, function(col) {
  col.addEventListener('dragstart', handleDragStart, false);
  col.addEventListener('dragenter', handleDragEnter, false);
  col.addEventListener('dragover', handleDragOver, false);
  col.addEventListener('dragleave', handleDragLeave, false);
});		
</script>

dragend事件

我们注意到上面dragstart的时候将透明度降低到40%,那在对应的在dragend要将透明度变回100%。另外还要处理dragenter时设置的虚线框。
另外在drop事件中要用e.stopPropagation()阻止浏览器默认事件。

  • A
  • B
  • C

dataTransfer

你注意到到现在我们拖来拖去似乎也没有真正拖动一个块到其他位置。是的,要实现这个需要在拖动过程中有个类似于数据传递的机制,dataTransfer对象的作用就是这个。
dataTransfer对象在dragstart事件中设置并可以在drop事件时读取和处理。
设置函数:e.dataTransfer.setData(format, data)
读取函数:e.dataTransfer.getData(format);
format是数据格式, 常用的格式有text/plain, image/jpeg, text/html, text/uri-list
在这个例子整个拖拽过程中,需要交换两个块的位置,也就是需要交换两个块的文字。那么就要在dragStart事件发生时获取被拖动块的DOM对象,并在拖动结束后将它的文字内容变成drop位置的块的文字。

var dragSrcEl = null;
function handleDragStart(e) {
  // Target (this) element is the source node.
  this.style.opacity = '0.4';
  dragSrcEl = this;
  e.dataTransfer.effectAllowed = 'move';
  e.dataTransfer.setData('text/html', this.innerHTML);
}
function handleDrop(e) {
  // this/e.target is current target element.
  if (e.stopPropagation) {
    e.stopPropagation(); // Stops some browsers from redirecting.
  }
  // Don't do anything if dropping the same column we're dragging.
  if (dragSrcEl != this) {
    // Set the source column's HTML to the HTML of the columnwe dropped on.
    dragSrcEl.innerHTML = this.innerHTML;
    this.innerHTML = e.dataTransfer.getData('text/html');
  }
  return false;
}
  • A
  • B
  • C

至此一个拖拽效果就实现了。咦,好像里面有些属性不认识。dataTransfer的常见属性如下:

dataTransfer.effectAllowed

该属性规定了元素可被操作的形式,属性值有:none, copy, copyLink, copyMove, link, linkMove, move, all, and uninitialized.
例子中用的是move,其他属性值还未做研究。

dataTransfer.dropEffect

相对于effectAllowed,用来设置元素可以被操作的类型,取值有none, copy, link, move.

e.dataTransfer.setDragImage(img element, x, y)

浏览器中元素被拖动时,会有一个类似于残影的效果,即”ghost image”,使用这个可以自定义该效果。例如换一个图片。

var dragIcon = document.createElement('img');
dragIcon.src = 'logo.png';
dragIcon.width = 100;
e.dataTransfer.setDragImage(dragIcon, -10, -10);

下面的例子在拖动时可以看到google的logo。

  • A
  • B
  • C


其他例子:http://html5demos.com/drag
参考:
http://www.html5rocks.com/en/tutorials/dnd/basics/
https://developer.mozilla.org/En/DragDrop/Drag_Operations
https://developer.mozilla.org/En/DragDrop/DataTransfer

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>