在HTML5推出拖放API之前,我们想要实现拖拽效果,一般都是使用mousedown、mousemove、mouseup鼠标事件监听来模拟出拖拽效果,代码量大,而且由于为了实时的拖拽效果而需要不断获取鼠标坐标位置和修改元素的位置,导致性能较差。而HTML5提供了原生的拖放API,无疑简单很多,而且性能较好。

HTML5的拖放API的兼容性如下:

http://caniuse.com/#feat=dragndrop

截图如下:

此处输入图片的描述

一. HTML5拖放事件处理的一般步骤

实现拖放一般步骤如下:

(1) 给被拖拽元素添加draggable属性;(dragable = "true")

<div id="source" draggable="true">source</div>

(2) 为目标元素添加一个dropzone属性;(可选)

<div id="divDropZone" dropzone="copy"></div>

(3) 在拖拽元素的dragstart初始化相关的数据信息,主要是DataTransfer对象;

source.ondragstart = function(e){
    e.dataTransfer.setData('test', 'testData');
};

(4) 在目标元素的dragover事件中,取消其默认操作;

target.ondragover = function(e){
    e.preventDefault(); 
};

(5) 在目标元素的drop事件中,处理接收到的数据;

target.ondrop = function(e){
    e.preventDefault();
    var elem = document.createElement('p');
    elem.innerHTML = e.dataTransfer.getData('test');
    e.target.appendChild(elem);
};

(6) 在被拖拽元素的dragend事件中,做善后工作;(可选)

如:

<!DOCTYPE html>
<html>
<head>
    <title>HTML5 拖拽</title>
    <style>
        #source{width:200px;height:200px;border:1px solid red;}
        #target{width:200px;height:200px;border:1px solid blue;}
    </style>
</head>
<body>
<div id="source" draggable="true">source</div>
<div id="target">target</div>

<script>
    var target = document.getElementById('target');
    var source = document.getElementById('source');
    source.ondragstart = function(e){
        e.dataTransfer.effectAllowed = 'copyMove';
        e.dataTransfer.setData('test', 'testData');
    };
    target.ondragover = function(e){
        e.dataTransfer.dropEffect = 'move';
        e.preventDefault(); // 阻止默认行为
    };
    target.ondrop = function(e){
        e.preventDefault();
        var elem = document.createElement('p');
        elem.innerHTML = e.dataTransfer.getData('test');
        e.target.appendChild(elem);
    };
</script>
</body>
</html>

二. 可拖动属性 —— draggable

HTML5为所有HTML元素规定了一个draggable属性,控制元素是否可以拖动。图像、链接和被选中的文本的draggable属性默认为true,其他元素默认为false。

draggable属性的值如下:

属性值 说明
true 内容可被拖动。
false 内容不可被拖动。
auto 内容执行默认的浏览器行为(图像、链接和被选中的文本可被拖动,其他元素不能)

支持 draggable 属性的浏览器有: IE9+、FF4+、Safari 5+、Chrome、Opera 12+。Opera 11.5- 不支持拖放功能。

draggable属性的兼容性处理:

(1) Firefox:需要添加ondragstart事件处理程序,并在dataTransfer中保存一些信息;

(2) IE9-通过mousedown事件调用dragDrop()能够让任何元素可拖动;

(3) Safari 4- 必须给相应元素设置 CSS 样式:

*[draggable = true] {
    -khtml-user-drag: element;
}

三. 放置目标元素属性 —— dropzone

dropzone可以创建一个放置区域。

属性值 作用
copy 表示将允许的元素放到该元素上时,会将拖拽数据复制到目标元素上。
move 表示将允许的元素放到该元素上时,会将数据移动到目标元素上。
link 表示将允许的元素放到该元素上时,将链接数据到目标元素上。

dropzone属性可以使用过滤器(filter),如:f:/img/png 表明只有png格式的图片文件才可以放置在此区域。

四. 拖放事件

拖放事件触发次序:

dragstart -> drag -> dragenter -> dragover -> dragleave -> drop -> dragend。

4.1 被拖动元素事件

拖动某元素时,将依次触发以下事件:

dragstart:按下鼠鼠标键并开始移动时,被拖动元素上触发 dragstart 事件;

drag:触发 dragstart 事件后,随即触发 drag 事件,而且元素拖动期间会持续触发该事件;

dragend:拖动停止时(释放鼠标、无论放置目标是否有效)触发 dragend 事件;

4.2 放置目标元素事件

当某个元素被拖动到一个有效的放置目标元素时,依次触发下列事件:

dragenter:元素进入到目标元素上时触发事件;

dragover:紧随 dragover 事件,被拖动元素在目标元素范围内移动时会持续触发该事件;

dragleave 或 drop:元素拖出了放置目标,则 dragover 事件不再发生,触发 dragleave 事件;如果被拖元素放到了目标元素上,则触发 drop 事件;

4.3 自定义放置目标

所有元素都支持放置目标事件,但多数元素默认是不允许放置的。重写 dragenter 和 dragover 事件的默认行为,可以把任何元素变成有效的放置目标。

dropArea.addEventListener("dragenter", preventDefault(event), false);  
dropArea.addEventListener("dragover", preventDefault(event), false);

// 阻止 Firefox 打开 URL
dropArea.addEventListener("drop", preventDefault(event), false);

// 阻止默认事件和事件冒泡
function preventDefault(event) { 
    event = event || window.event;
    event.stopPropagation();
    event.preventDefault();
}

Firefox 3.5+ 中,放置事件的默认行为是打开放到目标上的URL。如果是图像则打开图像,如果是文本则会导致无效 URL 错误(不安装拖拽插件的情况下)。所以还要取消 Firefox 中 drop 事件的默认行为,阻止它打开 URL。

注意1: drag和dragover是持续触发的。拖放文件到浏览器中时,需要在dragover和drop事件处理器中阻止默认行为(preventDefault())。因为从其他应用软件或是文件中拖东西进入浏览器中,默认的行为是浏览器将当前页面重定向到被拖拽元素所指向的资源上。

注意2: 在被拖元素上触发dragstart事件后,则该元素的mousemove,mouseover,mouseenter,mouseleave,mouseout事件均不会被触发了。

五. dataTransfer对象

dataTransfer对象是拖放事件对象的一个属性,用于从被拖动元素向放置目标传递字符串格式的数据。

5.1 dataTransfer 对象的方法

方法 说明
clearData(format) 清除以特定格式保存的数据 。
getData(format) 从 dataTransfer 对象中读取指定类型的值,参数是 MIME 类型。
setData(format, data) 为 dataTransfer 对象指定特定格式的数据,这些数据只能在 ondrop 处理程序中读取。
setDragImage(element, x, y) 指定一个元素拖动发生时显示在光标下方,三个参数分别是要显示的 HTML元素和光标在显示元素中的x、y坐标。
addElement(element) 为拖动操作添加一个元素(即增加作为拖动源而响应的回调对象)。如果想要让某个元素跟随被拖拽元素一同被拖拽,可使用该方法。

IE只定义了“text”和“URL”两种有效的数据类型,而HTML5则对此加以扩展,允许指定各种MIME类型。考虑到向后兼容,HTML5也支持“text”和“URL”,但这两种类型会被映射为“text/plain”和“text/uri-list”。如下所示:

text/html:文本文字格式;

text/plain:HTML代码格式;

text/xml:XML字符格式;

text/url-list:URL格式列表;

Firefox在其第5个版本之前不能正确地将“URL”和“text”映射为“text/uri-list”和“text/plain”。但是却能把“Text”映射为“text/plain”。为了更好地在跨浏览器的情况下从dataTransfer对象取得数据,最好在取得URL数据时检测两个值,而在取得文本数据时使用“text”。

var dataTransfer = event.dataTransfer; 
//读取URL 
var url = dataTransfer.getData("url") || dataTransfer.getData("text/uri-list"); 
//读取文本 
var text = dataTransfer.getData("Text");

5.2 dataTransfer对象的属性

Property Description
dropEffect 获取或设置被拖动元素能够执行哪中放置行为,不同的行为显示相应的光标。
effectAllowed 表示允许拖动元素的哪种 dropEffect。
files 返回被拖放文件的FileList对象。
types 返回ondragstart事件中传递的数据类型的类似数组的集合。

dropEffect的属性值分别有:

(1) none:不能放置拖动元素(除文本框以外所有元素的默认值);

(2) move:应该把元素移动到放置目标;

(3) copy:应该把拖动元素复制到放置目标;

(4) link:应该在放置目标上打开拖动元素(拖动元素必须是有 URL 的链接)。

effectAllowed的属性值分别有:

(1) uninitialized:被拖动元素没有设置放置行为;

(2) none:被拖动元素不允许有任何行为;

(3) copy:只允许 copy 值的 dropEffect;

(4) move:只允许 move 值的 dropEffect;

(5) copeLink:copy 和 link 值的 dropEffect;

(6) copeMove:copy 和 move 值的 dropEffect;

(7) linkMove:link 和 move 值的 dropEffect;

(8) all:允许任意 dropEffect。

使用dropEffect属性时必须在ondragenter中针对放置目标设置,只有搭配effectAllowed属性时才有用。必须在ondragstart中设置 effectAllowed。

本文作者:子匠_Zijor,转载请注明出处:http://www.dengzhr.com/frontend/html/535