Warning:
This wiki has been archived and is now read-only.
HTML5/dnd
Contents
拖放
本节定义了一种基于事件的拖放机制。
本规范并不精确地规定什么是实际的拖放操作。
在拥有定点设备的视觉媒体上,拖拽操作可以默认地定义为鼠标点下事件以及一系列后续的鼠标移动事件,释放操作可以释放鼠标触发。
在使用定点设备之外的输入形式时,用户可能必须要明确的表明他们执行拖放操作的意图,说明他们想要拖动什么、在什么地方释放。
无论如何实现,拖放操作必须拥有一个起始点(例如,鼠标在何处点击、选择的起始点或者被选为拖拽对象的元素),可以拥有任意数目的中间步骤(拖拽期间鼠标滑过的元素、用户在备选元素之间选择的可能的释放点),以及必选的一个结束点(释放鼠标按钮时所在的元素、或者最终选定的元素)或者取消。结束点必须为释放前最后选定的作为可能的释放点的元素(所以如果操作没有被取消,则其必须至少为中间步骤中的一个元素)。
介绍
本节不具规范性
很容易让一个元素可以被拖放:给元素设置一个draggable属性,并为储存被拖动数据的dragstart设置一个事件侦听器。
典型的事件处理器需要检查正在进行的拖动不是一个文本选择操作,并且需要将数据存入DataTransfer对象并设置允许的效果(复制、移动、链接,或者一些组合)。
举例说明:
<p>你喜欢的水果:</p> <ol ondragstart="dragStartHandler(event)"> <li draggable="true" data-value="fruit-apple">苹果</li> <li draggable="true" data-value="fruit-orange">橙子</li> <li draggable="true" data-value="fruit-pear">梨</li> </ol> <script> var internalDNDType = 'text/x-example'; // 设其为整个站点唯一的内容。 function dragStartHandler(event) { if (event.target instanceof HTMLLIElement) { // 使用元素的“data-value”属性作为要移动的值: event.dataTransfer.setData(internalDNDType, event.target.dataset.value); event.dataTransfer.effectAllowed = 'move'; // 仅允许移动 } else { event.preventDefault(); // 不允许拖动选择。 } } </script>
为了接受释放,释放对象需要拥有一个dropzone属性并坚挺drop
事件。
dropzone属性的值标识接受何种类型的数据(例如:“string:text/plain”接受任意文本字符串,或者“file:image/png”接受一个PNG图片文件)以及给出何种反馈(例如:“move”指示数据将被移动)。
drop事件允许执行实际的释放。该事件需要能够被取消,使得dropEffect属性的值可以被用于源(否则重置)。
举例说明:
<p>将你喜欢的水果放入下面:</p> <ol dropzone="move string:text/x-example" ondrop="dropHandler(event)"> <-- 不要忘记把“text/x-example”类型替换为全站唯一的值 --> </ol> <script> var internalDNDType = 'text/x-example'; // 设其为整个站点唯一的内容。 function dropHandler(event) { var li = document.createElement('li'); var data = event.dataTransfer.getData(internalDNDType); if (data == 'fruit-apple') { li.textContent = 'Apples'; } else if (data == 'fruit-orange') { li.textContent = 'Oranges'; } else if (data == 'fruit-pear') { li.textContent = 'Pears'; } else { li.textContent = 'Unknown Fruit'; } event.target.appendChild(li); } </script>
为了移除源元素(被拖动的)的显示,可以使用dragent事件。
在我们的例子中,这以为这更新源标签:
<p>你喜欢的水果:</p> <ol ondragstart="dragStartHandler(event)" ondragend="dragEndHandler(event)"> ...与之前相同... </ol> <script> function dragStartHandler(event) { // ...与之前相同... } function dragEndHandler(event) { // 移除被拖动的元素 event.target.parentNode.removeChild(event.target); } </script>
拖动数据储存
构成拖放操作的数据被称为拖动数据存储,其包含下列信息:
- 一个拖动数据存储元素列表,其为一个表示拖动数据的元素的列表,其中的每个元素包含下列信息:
- 下列信息用于在拖动中产生UI反馈:
- 用户代理定义的默认反馈信息,被称为拖动数据存储默认反馈。
- 零或多个元素的列表,被称为拖动数据存储元素列表。
- 可选的,一个位图图片以及图片中一个点的坐标,被称为拖动数据存储图片及拖动数据存储热点坐标。
- 一个拖动数据存储模式,其为下列值之一:
- 一个拖动数据存储允许的效果状态,且为一个字符串。
在创建一个拖动数据存储时,其必须初始化其拖动数据存储元素列表为空、没有拖动数据存储默认反馈、其拖动数据存储元素列表为空、没有拖动数据存储位图/拖动数据存储热点坐标、其拖动数据存储模式为受保护模式、且其拖动数据存储允许的效果状态为字符串“uninitialized”。
DataTransfer
接口
DataTransfer对象用于暴露基于拖放操作的拖拽数据存储。
interface DataTransfer { attribute DOMString dropEffect; attribute DOMString effectAllowed; readonly attribute DataTransferItemList items; void setDragImage(Element image, long x, long y); void addElement(Elementelement); /* 旧接口 */ readonly attribute DOMStringList types; DOMString getData(DOMString format); void setData(DOMString format, DOMString data); void clearData(optional DOMString format); readonly attribute FileList files; };
datatransfer . dropEffect [ = value ]
返回当前选择的操作类型。如果操作的类型不是effectAllowed属性所允许的类型之一,则操作将会失败。
可以设置,改变选定的操作。
可行的值包括“none
”、“copy
”、“link
”及“move
”
datatransfer . effectAllowed [ = value ]
返回允许的操作类型。
可以设置,改变允许的操作。
可行的值包括“none
”、“copy
”、“copyLink
”、“copyMove
”、“link
”、“linkMove
”、“move
”、“all
”和“uninitialized
”。
datatransfer . items
返回一个包含拖拽数据的DataTransferItemList对象。
datatransfer . setDragImage(element, x, y)
使用给出的元素替换拖拽反馈,替换之前制定的反馈。
datatransfer . addElement(element)
将给出的元素插入到用于渲染拖拽反馈的元素列表之中。
datatransfer . types
返回一个DOMStringList,其中列出了在dragstart事件中设置的格式。另外,如果拖拽了任意文件,则其中一个类型为字符串“Files
”.
data = datatransfer . getData(format)
返回指定的数据。如果没有这样的数据,则返回空字符串。
datatransfer . setData(format, data)
添加一个指定的数据。
datatransfer . clearData( [ format' ] )
移除指定格式的数据。如果忽略参数,则移除所有数据。
datatransfer . files
返回一个包含被拖拽的文件的FileList。
DataTransfer对象在拖放事件期间使用,并且仅在触发这些事件时有效。
一个DataTransfer对象在其有效时,与一个拖拽数据存储有关。
dropEffect属性控制在用户进行拖放操作期间的拖放反馈。在创建DataTransfer对象时,drapEffect属性被设为一个字符串值。在获取时,其必须返回其当前值。在设置时,如果新值为“none
”、“copy
”、“link
”或“move
”之一,则属性的当前值必须被设为新值。必须忽略其他值。
effectAllowed属性在拖放过程模式中用于在dragenter和dragover事件过程中初始化dropEffect属性。在创建DataTransfer对象时,effectAllowed属性被设为一个字符串值。在获取时,其必须返回其当前值。在设置时,如果新值为“none
”、“copy
”、“copyLink
”、“copyMove
”、“link
”、“linkMove
”、“move
”、“all
”或“uninitialized
”之一,则属性的当前值必须被设为新值。必须忽略其他值。
items属性必须返回一个与DataTransfer对象相关联的DataTransferItemList对象。必须每次返回同一个对象。
setDragImage(element, x, y)方法必须执行下列步骤:
- 如果DataTransfer对象没有与一个拖拽数据存储相关联,则跳过这些步骤。不发生任何事情。
- 如果拖拽数据存储的模式不是读写模式,则跳过这些步骤。不发生任何事情。
- 如果element参数为一个img元素,则设拖拽数据存储位图为该元素的图片(保留其原图大小);否则,设拖拽数据存储位图为由给出的元素所产生的图片(详细的工作机制不做指定)。
- 设拖拽数据存储热点坐标为给出的x、y坐标。
addElement(element)方法是指定用户代理如何渲染拖拽反馈的一种替代方式。该方法必须执行下列步骤:
- 如果DataTransfer对象没有与一个拖拽数据存储相关联,则跳过这些步骤。不发生任何事情。
- 如果拖拽数据存储的模式不是读写模式,则跳过这些步骤。不发生任何事情。
- 将给出的element插入到元素的拖拽数据存储元素列表之中。
types属性必须返回一个活跃的DOMStringList,其中给出下列步骤产生的字符串。每次返回的必须是同一个对象。
- 从空列表L开始。
- 如果DataTransfer对象没有与一个拖拽数据存储相关联,则DOMStringList为空。跳过这些步骤;返回空列表L。
- 对于拖拽数据存储项列表中类型为纯Unicode文本的每一项,向列表L添加一个包含项目的类型字符串的实体。
- 如果拖拽数据存储项列表存在类型为File的项目,则向列表L添加一个包含字符串“
Files
”的实体。(因为该字符串不是小写形式,所以它可以与其他值区分。) - 这些步骤所产生的字符串在列表L中。
getData(format)方法必须执行下列步骤:
- 如果DataTransfer对象没有与一个拖拽数据存储相关联,则返回空字符串并跳过这些步骤。
- 如果拖拽数据存储的模式为受保护模式,则返回空字符串并跳过这些步骤。
- 设格式为第一个参数,并转换为ASCII小写形式。
- 设转换为URL为假。
- 如果格式等于“
text
”,则将其改为“text/plain
”。 - 如果格式等于“
url
”,则将其改为“text/uri-list
”。 - 如果拖拽数据存储项列表中不存在类型为纯Unicode文本且类型字符串等于格式的项目,则返回空字符串并跳过这些步骤。
- 设结果为拖拽数据存储项列表中类型为纯Unicode文本且类型字符串等于格式的项目的数据。
- 如果转换为URL为真,则将结果按照
text/uri-list
数据解析,并且设结果为列表中的第一个URL(如果存在),或者空字符串。[RFC2483] - 返回结果。
setData(format, data)方法必须执行下列步骤:
- 如果DataTransfer对象没有与一个拖拽数据存储相关联,则跳过这些步骤。不发生任何事情。
- 如果拖拽数据存储的模式不是读写模式,则跳过这些步骤。不发生任何事情。
- 设格式为第一个参数,并转换为ASCII小写形式。
- 如果格式等于“
text
”,则将其改为“text/plain
”。
如果格式等于“url
”,则将其改为“text/uri-list
”。 - 移除拖拽数据存储项列表中类型为纯Unicode文本且类型字符串等于格式的项目。
- 向拖拽数据存储项列表中添加一个项目,其类型为纯Unicode文本、类型字符串等于格式且数据为方法的第二个参数给出的字符串。
clearData()方法必须执行下列步骤:
- 如果DataTransfer对象没有与一个拖拽数据存储相关联,则跳过这些步骤。不发生任何事情。
- 如果拖拽数据存储的模式不是读写模式,则跳过这些步骤。不发生任何事情。
- 如果调用方法时没有参数,则移除拖拽数据存储项列表中类型为纯Unicode文本的所有项目,并跳过这些步骤。
- 设格式为第一个参数,并转换为ASCII小写形式。
- 如果格式等于“
text
”,则将其改为“text/plain
”。
如果格式等于“url
”,则将其改为“text/uri-list
”。 - 移除拖拽数据存储项列表中类型为纯Unicode文本且类型字符串等于格式的项目。
files属性必须返回一个活跃的包含表示下列步骤所找出的文件的文件对象的FileList序列。每次必须返回同一个对象。另外,对于一个给出的FileList对象和一个给出的隐含文件,必须每次都返回同一个FileList对象。
- 从一个空列表L开始。
- 如果DataTransfer对象没有与一个拖拽数据存储相关联,则FileList为空。跳过这些步骤;返回空列表L。
- 如果拖拽数据存储的模式为受保护模式,则跳过这些步骤;返回空列表L。
- 对于拖拽数据存储项列表中类型为File的每一项,向列表L添加该项目数据(文件,特别是它的名称和内容,以及它的类型)。
- 这些步骤找到的文件在列表L中。
DataTransferItemList
接口
每个DataTransfer对象都有一个与之相关的DataTransferItemList对象。
interface DataTransferItemList { readonly attribute unsigned long length; getter DataTransferItem (unsigned long index); deleter void (unsigned long index); void clear(); DataTransferItem? add(DOMString data, DOMString type); DataTransferItem? add(File data); };
items . length
返回拖拽数据存储中项目的数量。
items[index]
返回表示拖拽数据存储中第index个实体的DataTransferItem对象。
delete items[index]
移除拖拽数据存储中的第index个实体。
items . clear()
移除拖拽数据存储中的所有实体。
items . add(data) items . add(data, type)
向拖拽数据存储中添加一个新的实体。如果数据为纯文本,则必须设置一个type字符串。
若DataTransferItemList对象的DataTransfer对象与一个拖拽数据存储相关,则DataTransferItemList对象的模式与拖拽数据存储模式相同。若DataTransferItemList对象的DataTransfer对象没有与一个拖拽数据存储相关联,则DataTransferItemList对象的模式为不可用模式。本节中对拖拽数据存储的引用(仅用于当DataTransferItemList对象不为不可用模式时)为与DataTransferItemList对象的DataTransfer对象相关联的拖拽数据存储。
如果对象处于不可用模式则length属性必须返回零;否则必须返回拖拽数据存储项列表中项目的数目。
若DataTransferItemList对象没有处于不可用模式,则其支持的数据索引为0至n-1范围内的数字,其中n为拖拽数据存储项列表中项目的数目。
为了决定一个DataTransferItemList对象的索引属性i的值,用户代理必须返回一个表示拖拽数据存储中第i个元素的DataTransferItem对象。每次必须返回同一个对象,特别是从DataTransferItemList对象得出的元素。DataTransferItem对象必须在DataTransferItemList对象第一次创建时与同一个DataTransfer对象向关联。
为了删除一个DataTransferItemList对象的索引属性i,用户代理必须执行下列步骤:
- 如果DataTransferItemList对象没有处于读写模式,则抛出一个InvalidStateError异常并终止这些步骤。
- 从拖拽数据存储中删除第i个项目。
如果DataTransferItemList对象处于读写模式,则clear方法必须从拖拽数据存储中删除所有项目。否则必须不进行任何操作。
add()方法必须执行下列步骤:
- 如果DataTransferItemList对象没有处于读写模式,则返回空并终止这些步骤。
- 跳转到下面的列表中适当的步骤:
- 如果第一个参数为字符串
- 如果拖拽数据存储项列表已经存在一个类型为纯Unicode字符串、类型字符串等于方法的第二个参数的项目(转换为ASCII小写形式),则抛出一个NotSupportedError异常并跳过这些步骤。
- 否则,向拖拽数据存储项列表添加一个项目,其类型为纯Unicode字符串、类型字符串等于方法的第二个参数(转换为ASCII小写形式)、数据为方法第一个参数给出的字符串。
- 如果第一个参数为File
- 如果第一个参数为字符串
- 决定新添加的项目的索引属性的值,并且返回该值(一个新的DataTransferItem对象)。
DataTransferItem
接口
每个DataTransfer对象都有一个与之相关的DataTransferItem对象。
interface DataTransferItem { readonly attribute DOMString kind; readonly attribute DOMString type; void getAsString(FunctionStringCallback? _callback); File? getAsFile(); }; [Callback, NoInterfaceObject] interface FunctionStringCallback { void handleEvent(DOMString data); };
item . kind
返回拖拽数据项类型,“string”、“file”之一。
item . type
返回拖拽数据项类型字符串。
item . getAsString(callback)
如果拖拽数据项类型为纯Unicode字符串,则使用该字符串数据作为参数请求回调函数。
file = item . getAsFile()
若DataTransferItem对象的DataTransfer对象与一个拖拽数据存储相关,且该拖拽数据存储的拖拽数据存储项列表仍然包含DataTransferItem对象表示的项目,则DataTransferItem对象的模式与拖拽数据存储模式相同。若DataTransferItem对象的DataTransfer对象没有与一个拖拽数据存储相关联,或者如果DataTransferItem对象所表示的项目已经从相关的拖拽数据存储列表中移除,则DataTransferItem对象的模式为不可用模式。本节中对拖拽数据存储的引用(仅用于当DataTransferItem对象不为不可用模式时)为与DataTransferItem对象的DataTransfer对象相关联的拖拽数据存储。
如果DataTransferItem对象处于不可以模式,则kind属性必须返回空字符串;否则必须返回返回下表中第一列包含DataTransferItem对象所表示的项目的拖拽数据项类型的行的第二列单元格中的字符串。
类型 | 字符串 |
---|---|
纯Unicode字符串 | “string” |
File | “file” |
如果DataTransferItem对象处于不可以模式,则type属性必须返回空字符串;否则必须返回DataTransferItem对象所表示的拖拽数据项类型字符串。
getAsString(callback)方法必须执行下列步骤:
- 如果callback为空,则跳过这些步骤。
- 如果DataTransferItem对象没有处于读写模式或只读模式,则跳过这些步骤。不调用回调函数。
- 如果拖拽数据项类型不是纯Unicode字符串,则跳过这些步骤。不调用回调函数。
- 否则,排入一个任务来调用callback,使用DataTransferItem对象所表示的项目的实际数据作为参数。
getAsFile()方法必须执行下列步骤:
- 如果DataTransferItem对象没有处于读写模式或只读模式,则返回空并跳过这些步骤。
- 如果拖拽数据项类型不是File,则返回空并跳过这些步骤。
- 返回一个新的File对象,该对象表示DataTransferItem对象所表示的项目的实际数据。
DragEvent
接口
拖放过程模式包含多个事件。它们都使用DragEvent接口。
[Constructor(DOMString type, optional DragEventInit eventInitDict)] interface DragEvent : MouseEvent { readonly attribute DataTransfer? dataTransfer; }; dictionary DragEventInit : MouseEventInit { DataTransfer? dataTransfer; };
DragEvent接口的dataTransfer属性必须返回其预置的值。在对象创建时,该属性必须被预置为空。其表示事件的上下文信息。
在用户代理需要在一个元素上触发一个名为e的拖放事件时,使用一个特定的拖拽数据存储,用户代理必须执行下列步骤:
- 如果e为dragstart,设拖拽数据存储模式为读写模式。
如果e为drop,设拖拽数据存储模式为只读模式。 - 设dataTransfer为一个新创建的DataTransfer对象,其关联至给出的拖拽数据存储。
- 设effectAllowed属性为拖拽数据存储的拖拽数据存储允许的效果状态。
- 如果e为dragstart、drag或dragleave,则设dropEffect属性为“
none
”;如果e为#event-drop或dragend,则设其为相应的当前拖拽操作;否则,其值根据effectAllowed属性的值和拖拽源,根据下表得出(例如,如果e为dragenter或dragover): - 创建一个DragEvent对象,并将其初始化为拥有给定的名称e、冒泡、如果e不是dragleave或dragend则可撤销、拥有预置为零的detail属性、按照用户交互事件的输入设备预置的鼠标及键盘属性、预置为空的relatedTarget属性、以及预置为dataTransfer(之前创建的DataTransfer对象)的dataTransfer属性。
- 将新创建的DragEvent对象指派给指定的目标元素。
- 将拖拽数据存储允许的效果状态设为dataTransfer的effectAllowed属性的当前值]]。
- 如果拖拽数据存储模式在第一步中被修改,则将其改回受保护模式。
- 破坏dataTransfer与拖拽数据存储之间的关联。
effectAllowed | dropEffect |
---|---|
“none ”
|
“none ”
|
“copy ”、“copyLink ”、“copyMove ”、“all ”
|
“copy ”
|
“link ”、“linkMove ”
|
“link ”
|
“move ”
|
“move ”
|
“uninitialized ”,当被拖拽的对象为一个文本字段中的选择。
|
“move ”
|
“uninitialized ”,当被拖拽的对象为一个选择。
|
“copy ”
|
“uninitialized ”,当被拖拽的对象为一个拥有href属性的a元素。
|
“link ”
|
任何其他情况 | “copy ”
|
拖放过程模式
在用户试图开始拖拽操作时,用户代理必须执行下列步骤。用户代理的操作必须像是这些步骤在运行,即使拖拽操作实际上起始于其他文档或应用,并且,在用户代理范围下,在拖拽操作进入文档之前用户代理不知道发生了拖拽操作。
- 确定被拖拽的对象:
- 创建一个拖拽数据存储。所有本节中随后触发的拖放事件必须使用此拖拽数据存储。
- 确定那个DOM节点为源节点:
- 确定拖拽节点的列表:
-
- 如果被拖拽的对象为选择器,则向拖拽数据存储项列表中插入一个项目,其属性如下:
- 拖拽数据项类型字符串
- “
text/plain
”
- “
- 拖拽数据项种类
- 纯Unicode字符串
- 实际数据
- 选择器的文本
- 拖拽数据项类型字符串
- 否则,如果被拖拽的对象是文件,则对于每个文件向拖拽数据存储项列表中插入一个项目,其属性如下:
- 拖拽数据项类型字符串
- 如果文件的MIME类型已知则为该值,否则为“
application/octet-stream
”
- 如果文件的MIME类型已知则为该值,否则为“
- 拖拽数据项种类
- 实际数据
- 文件的内容及名称注:对文件的拖拽实际上可以仅从浏览器上下文之外发生,例如从文件系统管理器应用中。
- 文件的内容及名称
- 拖拽数据项类型字符串
- 如果拖拽从应用之外开始,则当拖拽适当的数据时,用户代理必须向拖拽数据存储项列表中插入一个项目,遵守恰当的平台约定;无论如何,如果平台约定不使用MIME类型标记被拖拽的数据,则用户代理必须仅最大努力映射MIME类型,并且,在任意情况下,所有拖拽数据项类型字符串必须转换为ASCII小写形式。
- 如果被拖拽的对象为选择器,则向拖拽数据存储项列表中插入一个项目,其属性如下:
- 如果拖拽节点的列表不为空,则从这些节点中提取微数据到一个JSON表单中,并且向拖拽数据存储项列表中插入一个项目,其属性如下:
- 拖拽数据项类型字符串
- 拖拽数据项种类
- 纯Unicode字符串
- 实际数据
- 返回的JSON字符串。
- 执行下列子步骤:
- 设url为一个空的绝对URL列表。
- 对于拖拽节点的列表中的每一个节点:
- 如果url仍然为空,则跳过这些子步骤。
- 设url字符串为将url中的字符串连接的结果,按照他们被插入的顺序,以U+000D回车U+000A换行字符对(CRLF)分隔。
- 向拖拽数据存储项列表插入一个项目,其属性如下:
- 拖拽数据项类型字符串
- “
text/uri-list
”
- “
- 拖拽数据项种类
- 纯Unicode字符串
- 实际数据
- url字符串。
- 拖拽数据项类型字符串
- 如果被拖拽的对象是一个元素,则设拖拽数据存储元素列表仅包含源节点。
否则,反正用户代理适当地更新拖拽数据存储默认反馈(如果用户拖拽选择器,则选择器将很可能以此反馈最为基础;如果拖拽起始于用户代理之外,则平台约定应该使用的拖拽反馈)。注:脚本可以使用addElement()方法向被拖拽对象的列表中添加额外的元素。(该列表仅用于渲染拖拽反馈。) - 在源节点上触发一个拖放事件,其名为dragstart。
如果事件被撤销,则拖放操作应该没有发生;跳过这些步骤。注:因为事件没有注册事件监听器,按照定义,如果编码人员没有明确的阻止,不会被撤销,拖放对用户永远可用。 - 在于平台约定一直的机制下开始拖放操作。
拖放反馈必须由下列第一个可用的源产生:- 拖拽数据存储位图(如果存在)。在此情况下,拖拽数据存储热点坐标应当用作规定放置光标时相对与图片的位置。该值按照CSS像素从图片的左边和上边表示。[CSS]
- 拖拽数据存储元素列表中的元素(如果存在)。
- 拖拽数据存储默认反馈。
从用户代理初始化拖放操作开始,直到拖放操作结束,必须禁止驱动器输入事件(例如鼠标及键盘事件)。
在拖拽操作期间,作为拖拽目标直接显示给用户的元素被称为用户的直接选择。(仅有元素可以被用户选择;其他节点禁止被用作释放目标。)另外,用户的直接选择可以不是作为拖放操作释放部分的当前选择元素的当前目标元素。
用户的直接选择在用户选择不同元素时变化(使用定点设备指出或者通过其他途径选择)。当前目标元素在用户的直接选择改变时改变,其变化由之后描述的文档中的事件监听器的结果决定。
当前目标元素和用户的直接选择均可以为空,这意味着没有选择目标元素。它们也可以为其它(基于DOM的)文档、其他(为Web)程序中的元素。(例如,一个用户可以将文本拖拽至一个文本处理器中。)当前目标元素初始化为空。
另外,还存在一个当前拖拽操作,其值可能为“none
”、“copy
”、“link
”及“move
”。最初,其值为“none
”。其值的更新按照下面步骤中描述的由用户代理进行。
在拖拽操作初始化之后、拖拽操作进行中每隔350毫秒(正负误差200毫秒),用户代理必须按照下列步骤排入一个任务:
- 如果下一次迭代到期时用户代理仍然在处理序列中的上一次迭代,则跳过本次迭代中的这些步骤(实际上为对拖放操作“跳过错过的帧”)。
- 在源节点上触发一个拖放事件,该事件名为drag。如果该事件被撤销,用户代理必须将当前拖拽操作设为“
none
”(没有拖拽操作)。 - 如果drag事件没有被撤销,且用户没有结束拖放操作,则检查拖放操作的状态:
- 如果用户在上一次迭代时指定了不同的用户的直接选择(或者此次为第一次迭代),并且如果这个用户的直接选择与当前目标元素,则更新当前目标元素:
- 如果新的用户的直接选择为空
- 设当前目标元素同样为空。
- 如果新的用户的直接选择处于一个非DOM文档或应用
- 否则
- 如果新的用户的直接选择为空
- 如果上一步造成当前目标元素改变,并且如果之前的目标元素不为空或者非DOM文档的一部分,则在之前的目标元素上触发一个拖放事件,该事件名为dragleave。
-
- 如果当前目标元素是一个DOM元素,则在当前目标元素上触发一个拖放事件,该事件名为dragover。
- 如果dragover事件没有被撤销,则只需下列适当的步骤:
- 否则(如果dragover事件被撤销),则在事件指派完成之后根据DragEvent对象的dataTransfer对象的effectAllowed及dropEffect属性的值设置当前拖拽操作的值,其对应关系见下表一。
- 否则,如果当前目标元素不是一个DOM元素,则使用平台指定的机制来确定应该执行何种拖拽操作(none、copy、link或move),并依此设置当前拖拽操作。
- 更新拖拽反馈(例如鼠标指针)以匹配当前拖拽操作,其对应关系见下表二。
- 如果用户在上一次迭代时指定了不同的用户的直接选择(或者此次为第一次迭代),并且如果这个用户的直接选择与当前目标元素,则更新当前目标元素:
- 否则,如果用户结束拖放操作(例如在鼠标驱动的拖放接口中释放鼠标按键),或者如果drag事件被撤销,则其为上一次迭代。执行下列步骤,指标结束拖放操作:
-
- 如果当前拖拽操作为“
none
”(无拖拽操作),或者,如果用户结束拖放操作(例如点击Escape键),或者如果当前拖拽操作为空,则拖拽操作失败。执行这些子步骤: - 否则,拖拽操作可能成功;执行这些子步骤
- 设释放为真。
- 如果当前目标元素为一个DOM元素,则在其上触发一个拖放事件,该事件名为drop。否则,如果其不为空,则使用平台特定的约定进行释放。
-
- 如果事件被撤销,则设当前拖拽操作为在事件指派完成之后DragEvent对象的dataTransfer对象的dropEffect属性的值。
- 否则,事件没有被撤销;执行事件的默认操作,其由实际目标决定:
- 如果当前拖拽操作为“
- 在源节点上触发一个拖放事件,该事件名为dragend。
- 将下列适当的步骤作为dragend事件的默认行为执行:
- 如果释放为真,且当前目标元素为一个文本字段(例如textarea或type属性为文本状态的input元素),且当前拖拽操作为“
move
”,且拖放操作的源为DOM中的选择- 用户代理应当从DOM中删除拖拽选择器所表示的范围。
- 如果释放为真,且当前目标元素为一个文本字段(例如textarea或type属性为文本状态的input元素),且当前拖拽操作为“
move
”,且拖放操作的源为文本字段中的选择- 用户代理应当从相关文本字段中删除拖拽选择。
- 如果释放为假或者如果当前拖拽操作为“
none
”- 拖拽被撤销。如果平台约定指出这将向用户展示(例如用动画展示拖拽选择回到拖放操作的源),则按照约定操作。
- 否则
- 事件没有默认行为。
- 如果释放为真,且当前目标元素为一个文本字段(例如textarea或type属性为文本状态的input元素),且当前拖拽操作为“
-
事件摘要
本节不具规范性
下列事件属于拖放模型。
事件名称 | 目标 | 可撤销? | 拖拽数据存储模式 | dropEffect | 默认行为 |
---|---|---|---|---|---|
dragstart | 源节点 | 可撤销 | 读写模式 | “none ”
|
开始拖放操作 |
drag | 源节点 | 可撤销 | 受保护模式 | “none ”
|
继续拖放操作 |
dragenter | 直接的用户选择或者body元素 | 可撤销 | 受保护模式 | 由effectAllowed 的值决定
|
拒绝直接的用户选择作为可能的目标元素 |
dragleave | 上一个目标元素 | - | 受保护模式 | “none ”
|
无 |
dragover | 当前目标元素 | 可撤销 | 受保护模式 | 由effectAllowed 的值决定
|
重置当前拖拽操作为“none” |
drop | 当前目标元素 | 可撤销 | 只读模式 | 当前拖拽操作 | 不确定 |
dragend | 源节点 | - | 受保护模式 | 当前拖拽操作 | 不确定 |
上表没有列出:这些事件均冒泡,且effectAllowed属性的值总是上一个事件被触发之后拥有的值(dragstart事件中“uninitialized”)。
draggable
属性
所有HTML元素都可以设置draggable内容属性。draggable属性是一个枚举属性。它有三种状态。第一种状态为真,关键词为true
。第二种状态为假,关键词为false
。第三种状态为自动,没有关键词,但其为默认值。
状态真指该元素可拖拽;状态假指该元素不可被拖拽。状态自动则使用用户代理的默认行为。
element . draggable [ = value ]
如果元素可拖拽,则返回真;否则返回假。
可以被设置,覆盖默认状态并设置draggable内容属性。
draggable IDL属性的值由对于的内容属性按照下面的描述确定,控制元素是否可以被拖拽。通常只有文本选择可以被拖拽,但可以通过将元素的draggable IDL属性设为真,使其可以被拖拽。
如果元素的draggable内容属性处于状态真,则draggable IDL属性必须返回真。
否则,如果元素的draggable内容属性处于状态假,则draggable IDL属性必须返回假。
否则,元素的draggable内容属性处于状态自动。如果元素是一个img元素,或者如果元素是一个拥有href内容属性的a元素,则draggable IDL属性必须为真。
如果draggable IDL属性的值为假,则draggable内容属性的值必须为false
字面量。如果draggable IDL属性的值为真,则draggable内容属性的值必须为true
字面量。
dropzone
属性
所有HTML元素都可以设置dropzone内容属性。在指定其值时,其值必须为一个空格分隔的无序无重复的标记集合,其中的标记ASCII不区分大小写。其中允许的值如下:
- copy
- 表示将一个允许的项目释放到该元素上时,会将拖拽数据复制。
- move
- 表示将一个允许的项目释放到该元素上时,会将拖拽数据移动到新的位置。
- link
- 表示将一个允许的项目释放到该元素上时,将链接的源数据。
- 任意包含八个以上字符的关键词,且其由ASCII不区分大小写匹配字符串“
string:
”开始- 表示接受拖拽数据项类型为纯Unicode字符串、且拖拽数据项类型字符串被设为匹配关键词剩余部分的值,的项目。
- 任意包含六个以上字符的关键词,且其由ASCII不区分大小写匹配字符串“
file:
”开始- 表示接受拖拽数据项类型为File、且拖拽数据项类型字符串被设为匹配关键词剩余部分的值,的项目。
dropzone内容属性的值禁止指定超过一个的反馈值(copy、move和link)。如果没有指定,则相当于隐式的指定copy。
如果dropzone
处理步骤返回匹配,则dropzone属性匹配拖拽数据存储。
如果dropzone
处理步骤返回一个特定操作,则dropzone属性指定一个操作。特定的操作在这些步骤中给出。
dropzone
处理步骤如下。其返回是否匹配以及是否指定操作。
- 设值为dropzone属性的值。
- 设关键词集合为按空格分隔值的结果。
- 设匹配为假。
- 设操作为未指定。
- 对于关键词集合中的每个值(如果存在),按照其在值中被发现的顺序,执行下列步骤:
- 设关键词为该关键词。
- 如果关键词为“
copy
”、“move
”或“link
”,则执行下列子步骤:- 如果操作仍为未指定,则设操作为关键词给出的字符串。
- 跳转至关键词结束标记之后。
- 如果关键词不包含U+003A冒号字符(:),或者如果第一个这样的字符是关键词中的第一个字符或最后一个字符,则跳转至关键词结束标记之后。
- 设种类码为关键词中第一个字符到第一个U+003A冒号字符(:)之前的最后一个字符之间的子字符串,并转换为ASCII小写形式。
- 根据种类码跳转至下列适当的步骤:
- 如果种类码为字符串“
string
”- 设种类为纯Unicode字符串
- 如果种类码为字符串“
file
”- 设种类为File
- 否则
- 跳转至关键词结束标记之后。
- 如果种类码为字符串“
- 设类型为关键词中第一个U+003A冒号字符(:)之后的第一个字符到最后一个字符之间的子字符串,并转换为ASCII小写形式。
- 如果拖拽数据存储项列表中存在任意拖拽数据项种类为种类中给出的种类且拖拽数据项类型为类型的项目,则设匹配为真。
- 关键词结束:继续下一个关键词(如果存在),或者上层算法的下一步(如果没有更多关键词)。
- 如果匹配为真,则算法返回匹配,否则相反。
如果操作不是为未指定,则返回一个特定的操作。如果指定了一个特定操作,则该操作为操作中给出的一个。
dropzone IDL属性必须反映同名的内容属性。
在本例中,一个div元素使用dropzone属性成为图片文件的释放目标。释放在目标中的图片将在之后被显示。
<div dropzone="copy file:image/png file:image/gif file:image/jpeg" ondrop="receive(event, this)"> <p>将图片释放到这点以显示这些图片。</p> </div> <script> function receive(event, element) { var data = event.dataTransfer.items; for (var i = 0; i < data.length; i += 1) { if ((data[i].kind == 'file') && (data[i].type.match('^image/'))) { var img = new Image(); img.src = window.createObjectURL(data[i].getAsFile()); element.appendChild(img); } } } </script>
拖放模式中的安全风险
从dragstart事件对脚本可用到drop事件期间,用户代理禁止向DataTransfer对象中添加数据。因为如果不这样,当用户将敏感信息从一个文档拖动到另一个文档时,如果穿过了恶意的第三方文档,恶意文档就可以拦截这些数据。
因为同样的原因,用户代理必须考虑仅在用户明确地结束拖拽操作时才能成功释放——如果脚本结束拖拽操作,其必须经过考虑返回不成功(撤销)并且禁止触发drop事件。
用户代理应该主要不要再响应脚本行为时开始拖放操作。举例说明,在鼠标窗口环境中,如果脚本在用户点击鼠标按键时移动了窗口,用户代理不应该考虑开始拖拽。这相当重要,因为如果不这样,用户代理可能会造成数据在没有经过用户同意的情况下从敏感源中拖拽并释放在恶意文档中。
用户代理应该使用已知安全特性的白名单在拖拽和释放时过滤潜在的内容(例如HTML)变化(脚本)。本规范没有指定如果执行。