Web开发中的Drag&Drop完全手册

来源:互联网 发布:java电商平台源码 编辑:程序博客网 时间:2024/04/28 18:42

    Web开发中的Drag&Drop完全手册

  转自:http://www.cnblogs.com/birdshome/archive/2006/07/22/Drag_Drop.html

这几天做了一些drag&drop操作方面的工作,在这里把一些注意事项记录下来,算是给自己备个忘,也给需要做类似工作的人留个树阴。这里要讨论的drag&drop是指使用IE提供的内置机制,而不是使用鼠标模拟的那种"假"drag&drop,比如移动一个div或span的效果那种。

    要实现和控制drag&drop操作,那么首先第一点要弄清楚的是,到底哪些元素是可以在Web上被drag的?实际上IE默认给我们并让我们drag的元素并不多,它们是:图片选中的文字(包括页面文字和文字控件(input, textarea)中的文字)和连接(普通连接和锚点)。除此之外,别的Web元素默认都不支持drag操作(在这些元素上面drag其实就是选择操作了),所以要实现对元素默认的drag&drop控制,只能选这3类元素来操作。

    
在BizStruct同学的斧正中提到,其实几乎所有的Html元素都是支持drag&drop的(见其回复),在此表示由衷的感谢。

    接下来,那么哪些元素又是可以接受drop操作呢?任何页面上的可见元素都是可以接受drop操作的,而它们之间的不同只是在于默认的drop事件不一样。比如,文字控件(input, textarea)的默认drop事件就是获取drag操作传过来的文字内容;iframe元素的默认drop操作是到航道drag操作传过来的URL地址。当然绝大多数的Web元素的默认是操作是do nothing,什么也不做。

    那么当进行drag&drop操作时,有那些是可控制和定制的内容呢?这里关于drag&drop提供了以下一些事件(我们把它们分为作用于来源对象目的对象来分别讨论),先讨论主要作用于来源对象的事件:
   ·ondrag —— 在整个从drag动作开始,直道drop动作结束的过程中,都会触发的一个事件。
   ·ondragstart —— 在drag动作开始时,在来源对象上触发的一个事件。
   ·ondragend —— 在drop动作结束的时候,在来源对象上出发的一个事件。

   而主要做要在目的对象上的事件:
   ·ondragenter —— 在drag动作进入某一有效目的元素时,在该目的元素上触发的一个事件。
   ·ondragover —— 在drag动作进入某一有效目的元素后,在该目的元素上触发的一个事件。
   ·ondragleave —— 在drag动作离开某一有效目的元素时,在该目的元素上触发的一个事件。
   ·ondrop —— 在任何有效目的元素上进行drop操作时,在该目的元素上触发的一个事件。

    这里的来源和目的的划分不是绝对的,比如ondragover事件,在drag操作过程中,如果鼠标进入了来源对象中,同样的也会触发这个事件。这些事件触发的顺序是:来源对象 --> ondragstart --> ondrag --> ondragend;目的对象 --> ondragenter --> ondragover --> ( ondragleave | ondrap )。由于是分别在同一个对象上触发的事件,所以这个顺序很简单。那么对于一个完整的从来源对象到目的对象的drag&drop操作来说,事件的触发序列又是怎样呢?如果src表示来源对象,des表示目的对象,那么事件触发序列为:

    src:ondragstart --> src:ondrag --> des:ondragenter --> des:ondragover --> ( des:ondragleave | des:ondrop ) --> src:ondragend.

    示例为:
Drag Source Drop Destination
    // 如果alert窗口不响应鼠标点击可以使用键盘的space键来确定窗口

<onmouseover="status=this.innerText; return true;" ondragend="alert('src:on'+event.type)" onclick="return false;">Drag Source</A>
<SPAN ondrop="alert('des:on'+event.type)" ondragleave="alert('des:on'+event.type)">Drop Destination</SPAN>


    了解了事件触发顺序后,定制drag&drop过程中鼠标的光标形状也是非常重要的一个内容。因为用户的drag&drop的整个过程都需要靠鼠标光标的形状指导其进行操作,如果不能实时的调整光标为适合的型状,drag&drop操作对用户来说将无异于朦眼寻物。IE提供了用来控制的drag&drop过程中光标形状的两个属性,它们是:effectAllowed和dropEffect。

    其属性分别为:
        ·effectAllowed: copy, link, move, copyLink, copyMove, all, none & uninitialized.
        ·dropEffect: copy, link, move, none.

    前者effectAllowed是用来控制允许drag&drop操作类型的,所以这里的effect不是显示的"效果",而是是否可以执行的"操作",并且该属性只能在ondragstart事件中进行初始化,之后再对其赋值将无效。当然如果只使用effectAllowed属性,就已经可以达到控制光标形状的作用了。只是effectAllowed属性在处理复合操作时,比如copyLink, copyMove和all,会默认显示靠前那个操作类型的鼠标类型。也就是说如果effectAllowed是copyMove,那么这是鼠标光标就是copy形状。这下就知道为什么还要弄个dropEffect属性了吧?不过这个dropEffect属性中指定的effect,只能是之前effectAllowed允许的操作类型范围中的值,否则没有效果(显示no-drop鼠标光标)。
    
    示例为:
Drag Source Drop Destination

<ondragstart="event.dataTransfer.effectAllowed='copyMove'; event.dataTransfer.dropEffect='move'" onmouseover="status=this.innerText; return true;" ondragover="event.dataTransfer.dropEffect='move'; event.returnValue=false; event.cancelBubble=true;" onclick="return false;">Drag Source</A>
<SPAN ondragover="event.dataTransfer.dropEffect='copy'; event.returnValue=false; event.cancelBubble=true;">Drop Destination</SPAN>


    查看代码时注意,你会发现在src和des的对象元素中,在ondragover事件里除了对dropEffect赋以适当的值外,还有两句话:

   event.returnValue=false;
   event.cancelBubble
=true;


    只是由于页面元素在接受dragover的时候,本身都有其默认的鼠标光标显示型状,所以为了让用户自定义的鼠标光标生效,就需要使事件event的returenValue为false值并停止当事件的冒泡(event.cancelBubble=true)。

    到目前为止,一个完整的drag&drop过程就差数据传递了,其实忙活了半天,这才是藏在所有交互操作和显示效果下面最重要的步骤。这个过程需要借助于IE提供的DHTML Data Transfer对象来完成,在window对象的属性event对象中,分别有两个Data Transfer对象各自的一个实例:一个叫dataTransfer,另一个叫clipboardData。这两个对象实例的行为非常相似,但又有一些区别,clipboardData顾名思义,它使用操作系统的剪贴板来存取数据,并有3个方法;而dataTransfer通过操作一个自己的内部剪贴板来存取数据(每次ondragend事件触发后就自动清空了),除了有和clipboardData相同的3个方法外,还有两个属性(就是前面介绍的那两个effectAllowed和dropEffect)。

    我们这里不对clipboardData作更多的讨论,继续来看dataTransfer对象。它包含3个方法,它们是:setData(sDataFormat, sText), getData(sDataFormat)和clearData([sDataFormat])。它们更详细的使用和参数请参阅MSDN,这里我只用它们来实现drag&drop的数据传递。

    示例为:
Drag Source Drop Destination

<ondragstart="event.dataTransfer.effectAllowed='copyMove'; event.dataTransfer.dropEffect='move'; event.dataTransfer.setData('TEXT', this.innerText);" onmouseover="status=this.innerText; return true;" ondragover="event.dataTransfer.dropEffect='move'; event.returnValue=false; event.cancelBubble=true;" onclick="return false;">Drag Source</A>
<SPAN ondrop="this.innerText = event.dataTransfer.getData('TEXT'); this.style.color = 'red';" ondragover="event.dataTransfer.dropEffect='copy'; event.returnValue=false; event.cancelBubble=true;">Drop Destination</SPAN>


    其实很简单,就是在src的ondragstart中,调用event.dataTransfer.setData('TEXT', this.innerText),然后再des的ondrop事件中,调用this.innerText = event.dataTransfer.getData('TEXT')就行了。

评论

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

可以去查一下 dragDrop 这个方法,有几十个元素支持,这些元素都支持 Drag&Drop,而不仅仅是你说的三种,否则微软没有必要提供这个方法。这些元素虽然都可以 Drag&Drop,但简单的应用只能拖拽文本,而高级的应用,比如拖拽控件,就需要一些技巧,这些网上都有很多应用。
另外你的第一个演示,如果拖拽 Drag Source 到 Drop Destination,再移出,会弹出 ondragleave 的 alert,这时这个 IE 窗口中 的鼠标就会被锁死,只有键盘能操作。
2006-07-23 11:00 | BizStruct

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

@BizStruct 您好可以提供
Drag&Drop 的实例吗
2006-07-23 12:33 | 高海东

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

@BizStruct
非常感谢您的斧正,不过在正常模式的页面下,我确实无法drag&drop这三个以外的元素(除非使用controlRange来选中它们,但是这样即使选中也不能进行普通的drag&drop)。当然如果开启了block元素的contenteditable属性,确实可以drag&drop容器中任意的元素,不过这些元素无法用过event.dataTransfer访问到,那么怎么使用呢?还望指教。

// 另外,网上搜Web上的drag&drop,出来的全都是mousemove那种东西。
2006-07-23 14:21 | birdshome

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

因为 dataTransfer 中只能保存文本,所以微软缺省只提供了你说的那三种元素的拖拽,其他元素的拖拽必须自己实现。
第一步是调用元素的 dragDrop(),应该在鼠标按下刚开始移动的时候。
第二步是响应 ondragstart 事件,设置 dataTransfer 中拖拽的文字。
后面的步骤就和系统缺省的拖拽一样了。
下面是一个可以拖拽标题的按钮。

<button onmousedown="event.srcElement.dragDrop();" ondragstart="event.dataTransfer.setData('Text', event.srcElement.value); event.dataTransfer.effectAllowed = 'CopyMove'; event.dataTransfer.dropEffect = 'move';">拖拽</button>

如果想拖拽元素,就要在 dataTransfer 中作文章,保存的文字是元素的id,在 drop 的时候,根据 id 找到被拖拽的元素,进行移动。
在我们的网站上的特性展示里有表格行拖拽的演示。
2006-07-23 15:00 | BizStruct

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

想收藏一下,没找到按钮,只能这样先留个记号了。
2006-07-23 21:18 | 随心所欲

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

来点高档点的吧,实现TreeView的节点的拖放到TextBox中,要传递Text和value
2006-07-24 20:17 | Herry

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

@Herry
楼主已经把drag&drop讲的如此清楚了,你那点所谓的需求只能说是幼稚啊
2006-09-12 11:44 | assi

# 能否从下拉框中拖拽一个选项到一个文本框,松开鼠标后,将内容插入鼠标的位置?  回复  更多评论   

能否从下拉框中拖拽一个选项到一个文本框,松开鼠标后,将内容插入鼠标的位置?
2007-01-12 13:15 | 问题

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

@问题
DropDownList,即html中的<select>下的<option>是不能drag&drop的。
2007-01-12 14:29 | birdshome

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

我要实现的功能是这样的:
列表形式的下拉框中鼠标拖动一个选项,获取这个选项的表示文字,拖拽到一个文本框的插入位置,松开鼠标后,将内容插入文本框中鼠标的位置?.

不是拖动列表,而是获取鼠标选中的列表项内容,通过拖拽的形式插入文本框中.

请教:这样的功能是否能够实现,大致该如何做,谢谢
2007-01-12 14:51 | 问题

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

@问题
窗口元素Select、Option或Iframe一类,是没有ondragstart事件的,所以不能对其直接进行drag&drop操作。
一般的做法,可以用一个额外的按钮来复制你选中的Select条目的值。
2007-01-12 16:17 | birdshome

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

非常感谢,我尝试一下其他的变通方法.
2007-01-12 16:23 | 问题

# re: Web开发中的Drag&Drop完全手册  回复  更多评论   

请教:
有一表格或其他能够表示多项数据的页面元素.
现在必须选择这些元素中的数据(呈现蓝色反色),然后拖拽才能触发Drag&Drop事件.
是否能够直接让鼠标拖拽其中数据(不是选择后拖拽)就能触发Drag&Drop事件呢?比如拖拽表格中的某行,就能够触发Drag&Drop事件,从而得到该行数据?
2007-01-13 16:35 | 问题

 

原创粉丝点击