最近要在项目中做拖动排序,暂时用插件实现了此功能,在这里详细了解下html与js关于拖动的那些事

在HTML5之前,如果要实现一个元素的拖放效果,需要结合 onmousedown 、 onmousemove 、 onmouseup 事件,还有鼠标位置获取的知识点,来完成元素的拖动的效果。所以很麻烦。在HTML5中,只要将某个元素的 draggable 属性设置为 true ,该元素就可以实现拖放的效果。并且拖放过程中也能触发很多事件。

默认情况下,浏览器都是支持drag & drop API的,图像、链接和文本是可以拖动的,也就是说,不用额外编写代码,用户就可以拖动它们,拖动带链接的图片或链接到地址栏,就会在新页面大口袋式图片和链接。图像和链接要置顶链接,而文本在被选中的情况下也能拖动。

对于Safari,还必须要在CSS中对能拖拽的元素如下设置:

元素在拖放过程中触发的事件

拖动总共有7个事件,其中事件主体是拖放元素,dragstart(开始拖动) 、darg(正在拖放) 、dragend(拖放结束),其他4个事件主体都是目标元素,进入、移动、离开、完全进入四个状态,如下所示

  1. dragstart:事件主体是被拖放元素,在开始拖放被拖放元素时触发,。
  2. darg:事件主体是被拖放元素,在正在拖放被拖放元素时触发。
  3. dragenter:事件主体是目标元素,在被拖放元素进入某元素时触发。
  4. dragover:事件主体是目标元素,在被拖放在某元素内移动时触发。
  5. dragleave:事件主体是目标元素,在被拖放元素移出目标元素是触发。
  6. drop:事件主体是目标元素,在目标元素完全接受被拖放元素时触发。
  7. dragend:事件主体是被拖放元素,在整个拖放操作结束时触发。

为了减少事件,你可以在事件 ondragenter 的时候 绑定方法 ,而 ondragleave 的时候,删除 方法。最好不要绑定在 dragover 上,它就像 mouseover ,在拖动的过程中不断触发,对于浏览器的负担就很大了,浏览器还有可能崩溃。

dataTransfer对象

实现拖放最终是为了改变数据的顺序,只有简单的拖放而没有数据变化是没有什么用的。为了在拖放操作时实现数据交换HTML5定义了dataTransfer对象来传递拖拽的数据。

因为它是事件对象的属性,所以只能在拖放事件的事件处理程序中访问dataTransfer对象。在事件处理程序中,可以使用这个对象的属性和方法来完善拖放功能。

getData()和setData()

dataTransfer对象有 getData()和setData()两个主要方法,操作dataTransfer中携带的数据。不难想象,getData()可以取得由setData()保存的值。setData()方法的第一个参数,也是getDAta()方法唯一的一个参数,表示保存的数据类型。

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格式列表

实际上,dataTransfer对象可以为每种MIME类型都保存一个值。换句话说,同时在这个对象中保存了一段文本和一个URL不会有任何问题。不过,保存在dataTransfer对象中的数据只能在drop事件处理程序中读取。如果在ondrop处理程序中没有读到数据,那就是dataTransfer对象已经被销毁,数据也丢失了。

在拖动文本框中的文本时,浏览器会调用setData()方法,将拖动的文本以“text”格式保存在dataTransfer对象中。类似地,在拖放链接或图像时,会调用setData()方法并保存URL。然后,在这些元素被拖放到放置目标时,就可以通过getData()读到这些数据。当然,作为开发人员,你也可以在dragstart事件处理程序中调用setData(),手工保存自己要传输的数据,以便将来使用。

将数据保存为文本和保存为URL是有区别的。如果将数据保存为文本格式,那么数据不会得到任何特殊处理。而如果将数据保存为URL,浏览器会将其当成网页中的链接。换句话说,如果你把它放置到另一个浏览器窗口中,浏览器就会打开该URL。

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

注意:一定要把短数据类型放在前面,因为IE 10及之前的版本仍然不支持扩展的MIME类型名,而它们在遇到无法识别的数据类型时,会抛出错误。

使用 setDragImage 方法设置拖放图标

在HTML5中,一个元素在被拖放时,还可以自定义拖放元素的鼠标图标。调用格式如下:

setDragImage调用格式

img表示拖放时的 <> 元素的图标,x 表示图标距离鼠标指针的x轴方向的偏移值,y表示图标距离鼠标指针y轴方向的偏移值。

使用 effectAllowed 和 dropEffect 属性设置拖放效果

dataTransfer对象的两个属性:dropEffect和effectAllowed,能通过它来确定被拖动的元素以及作为放置目标的元素能够接受什么操作。结合effectAllowed 和 dropEffect 这两个属性,可以自定义拖放过程中的效果。两个属性虽然都是为了实现同一功能,但绑定的元素不同:effectAllowed属性作用于被拖放元素;而 dropEffect 属性作用于目标元素。

通过dropEffect属性可以知道被拖动的元素能够执行哪种放置行为。这个属性有下列4个可能的值。

  • none:不能把拖动的元素放在这里。这是除文本框之外所有元素的默认值。
  • move:应该把拖动的元素移动到放置目标
  • copy:应该把拖动的元素复制到放置目标
  • link:表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,有URL)。

在把元素拖动到放置目标上时,以上每一个值都会导致光标显示为不同的符号。然而,要怎样实现光标所指示的动作完全取决于你。换句话说,如果你不介入,没有什么会自动地移动、复制,也不会打开链接。总之,浏览器只能帮你改变光标的样式,而其它的都要靠你自己来实现。要使用dropEfect属性,必须在ondraggenter事件处理程序中针对放置目标来设置它。

dropEffect属性只有搭配effectAllowed属性才有用。effectAllowed属性表示允许拖放元素的哪种dropEffect,effectAllowed属性可能的值如下。

  • uninitialized:没有该被拖动元素放置行为。
  • none:被拖动的元素不能有任何行为。
  • copy:只允许值为“copy”的dropEffect。
  • link:只允许值为“link”的dropEffect。
  • move:只允许值为“move”的dropEffect。
  • copyLink:允许值为“copy”和“link”的dropEffect。
  • copyMove:允许值为“copy”和”link”的dropEffect。
  • linkMove:允许职位“link”和”move”的dropEffect。
  • all:允许任意dropEffect。

必须在ondraggstart事件处理程序中设置effectAllowed属性。

假设你想允许用户把文本框中的文本拖放到一个<div>元素中。首先,必须将dropEffect和effectAllowed设置为”move”。但是,由于<div>元素的放置事件的默认行为是什么也不做,所以文本不可能自动移动。重写这个默认行为,就能从文本框中移走文本。然后你就可以自己编写代码将文本插入到<div>中,这样整个拖放操作就完成了。如果将dropEffect和effectAllowed的值设置为”copy”,那就不会自动移走文本框中的文本。

其它属性

  • addElement:事件主体是被拖放元素,为拖动操作添加一个元素。添加这个元素只影响数据(即增加作为拖动源而影响回调的对象),不会影响拖动操作时页面元素的外观。在写作文本时,只有Firefox 3.5+实现了这个方法。
  • clearData:事件主体是目标元素,清除以特定格式保存的数据。实现这个方法的浏览器有IE、Firefox 3.5、Chrome和Safari 4+。
  • types:当前保存的数据类型。这是一个类似数组的集合,以“text”这样的字符串形式保存着数据类型。实现这个属性的浏览器有IE10+、Firefox 3.5+和Chrome。

支持draggable属性的浏览器有IE10+、Firefox 4+、Safari 5+和Chrome。Opera 11.5以及之前的版本都不支持HTML5的拖放功能。另外,为了让Firefox 支持可拖动属性,还必须添加一个ondragstart事件处理程序,并在dataTransfer对象中保存了一些信息。

示例

步骤1:创建一个可拖拽对象

下面是要采用的步骤:

  • 如果想要拖动某个元素,需要设置元素的 draggable 属性为 true。
  • 给 dragstart 设置一个事件监听器存储拖拽数据。
  • 事件监听器 dragstart 会设置允许的效果(copy,move,link或者是组合形式的)。

效果如下

步骤2:放置对象

为了接受放置,放置目标至少要监听三个事件。

  • dragenter 事件,用来确定放置目标是否接受放置。如果放置被接受,那么这个事件必须取消。
  • dragover 事件,用来确定给用户显示怎样的反馈信息。如果这个事件被取消,反馈信息(通常就是光标)就会基于 dropEffect 属性的值更新。
  • 最后是 drop 事件,允许执行真是的放置。

下面是把一个对象放入另一个对象的示例:

效果如下

关于js拖动功能,下期介绍

发表评论

电子邮件地址不会被公开。 必填项已用*标注