动态标准 — 最后更新于 2024年9月12日
所有当前引擎都支持。
本节定义了一种基于事件的拖放机制。
本规范未定义拖放操作的具体含义。
在具有指向设备的可视媒体上,拖动操作可能是mousedown
事件的默认操作,随后是一系列mousemove
事件,并且释放鼠标可以触发放置操作。
当使用除指向设备之外的输入方式时,用户可能需要明确指示其执行拖放操作的意图,分别说明他们希望拖动什么以及希望将其放置在哪里。
无论如何实现,拖放操作都必须有一个起点(例如,鼠标单击的位置,或选择或元素开始拖动的位置),可以有任意数量的中间步骤(元素在拖动过程中鼠标移动到的元素,或用户在循环浏览可能性时选择为可能的放置点的元素),并且必须有一个终点(鼠标按钮释放上方的元素,或最终选择的元素),或者被取消。终点必须是在放置操作发生之前作为可能的放置点选择的最后一个元素(因此,如果操作未被取消,则中间步骤中必须至少有一个元素)。
本节是非规范性的。
要使元素可拖动,请为该元素添加draggable
属性,并为dragstart
设置事件侦听器,以存储正在拖动的的数据。
事件处理程序通常需要检查它是否不是正在拖动的文本选择,然后需要将数据存储到DataTransfer
对象中并设置允许的效果(复制、移动、链接或某种组合)。
例如
< p > What fruits do you like?</ p >
< ol ondragstart = "dragStartHandler(event)" >
< li draggable = "true" data-value = "fruit-apple" > Apples</ li >
< li draggable = "true" data-value = "fruit-orange" > Oranges</ li >
< li draggable = "true" data-value = "fruit-pear" > Pears</ li >
</ ol >
< script >
var internalDNDType = 'text/x-example' ; // set this to something specific to your site
function dragStartHandler( event) {
if ( event. target instanceof HTMLLIElement) {
// use the element's data-value="" attribute as the value to be moving:
event. dataTransfer. setData( internalDNDType, event. target. dataset. value);
event. dataTransfer. effectAllowed = 'move' ; // only allow moves
} else {
event. preventDefault(); // don't allow selection to be dragged
}
}
</ script >
要接受放置,放置目标必须侦听以下事件
dragenter
事件处理程序通过取消事件报告放置目标是否可能愿意接受放置。dragover
事件处理程序通过设置与事件关联的DataTransfer
的dropEffect
属性来指定将向用户显示的反馈。此事件也需要被取消。drop
事件处理程序有最后一次机会接受或拒绝放置。如果接受放置,则事件处理程序必须对目标执行放置操作。此事件需要被取消,以便dropEffect
属性的值可以被源使用。否则,放置操作将被拒绝。例如
< p > Drop your favorite fruits below:</ p >
< ol ondragenter = "dragEnterHandler(event)" ondragover = "dragOverHandler(event)"
ondrop = "dropHandler(event)" >
</ ol >
< script >
var internalDNDType = 'text/x-example' ; // set this to something specific to your site
function dragEnterHandler( event) {
var items = event. dataTransfer. items;
for ( var i = 0 ; i < items. length; ++ i) {
var item = items[ i];
if ( item. kind == 'string' && item. type == internalDNDType) {
event. preventDefault();
return ;
}
}
}
function dragOverHandler( event) {
event. dataTransfer. dropEffect = 'move' ;
event. preventDefault();
}
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 >
要从显示中删除原始元素(即被拖动的元素),可以使用dragend
事件。
对于我们这里的示例,这意味着更新原始标记以处理该事件
< p > What fruits do you like?</ p >
< ol ondragstart = "dragStartHandler(event)" ondragend = "dragEndHandler(event)" >
...as before...
</ ol >
< script >
function dragStartHandler( event) {
// ...as before...
}
function dragEndHandler( event) {
if ( event. dataTransfer. dropEffect == 'move' ) {
// remove the dragged element
event. target. parentNode. removeChild( event. target);
}
}
</ script >
构成拖放操作基础的数据,称为拖放数据存储,包含以下信息
一个拖放数据存储项列表,它是一个表示拖动数据的项列表,每个项包含以下信息
数据的类型
文本。
具有文件名的二进制数据。
一个 Unicode 字符串,给出数据的类型或格式,通常由MIME 类型给出。出于遗留原因,某些不是MIME 类型的值是特殊处理的。API 不强制使用MIME 类型;也可以使用其他值。但是,在所有情况下,API 都会将所有值转换为 ASCII 小写。
每个项类型字符串最多只能有一个文本项。
一个 Unicode 或二进制字符串,在某些情况下带有一个文件名(本身是一个 Unicode 字符串),根据拖放数据项类型。
拖放数据存储项列表按项添加到列表中的顺序排序;最近添加的项在最后。
以下信息,用于在拖动过程中生成 UI 反馈
一个拖放数据存储模式,它可以是以下之一
一个拖放数据存储允许的效果状态,它是一个字符串。
当拖放数据存储创建时,必须将其初始化,使其拖放数据存储项列表为空,没有拖放数据存储默认反馈,没有拖放数据存储位图和拖放数据存储热点坐标,其拖放数据存储模式为保护模式,其拖放数据存储允许的效果状态为字符串“uninitialized
”。
DataTransfer
接口所有当前引擎都支持。
DataTransfer
对象用于公开构成拖放操作基础的拖放数据存储。
[Exposed =Window ]
interface DataTransfer {
constructor ();
attribute DOMString dropEffect ;
attribute DOMString effectAllowed ;
[SameObject ] readonly attribute DataTransferItemList items ;
undefined setDragImage (Element image , long x , long y );
/* old interface */
readonly attribute FrozenArray <DOMString > types ;
DOMString getData (DOMString format );
undefined setData (DOMString format , DOMString data );
undefined clearData (optional DOMString format );
[SameObject ] readonly attribute FileList files ;
};
dataTransfer = new DataTransfer()
所有当前引擎都支持。
使用空拖放数据存储创建一个新的DataTransfer
对象。
dataTransfer.dropEffect [ = value ]
所有当前引擎都支持。
返回当前选定的操作类型。如果操作类型不是effectAllowed
属性允许的操作类型之一,则操作将失败。
可以设置,以更改选定的操作。
dataTransfer.effectAllowed [ = value ]
所有当前引擎都支持。
返回要允许的操作类型。
可以在(dragstart
事件期间)设置,以更改允许的操作。
可能的值为 "none
"、"copy
"、"copyLink
"、"copyMove
"、"link
"、"linkMove
"、"move
"、"all
" 和 "uninitialized
"。
dataTransfer.items
所有当前引擎都支持。
返回一个 DataTransferItemList
对象,其中包含拖动数据。
dataTransfer.setDragImage(element, x, y)
所有当前引擎都支持。
使用给定的元素更新拖动反馈,替换任何先前指定的反馈。
dataTransfer.types
所有当前引擎都支持。
返回一个 冻结数组,其中列出了在 dragstart
事件中设置的格式。此外,如果正在拖动任何文件,则其中一个类型将是字符串 "Files
"。
data = dataTransfer.getData(format)
所有当前引擎都支持。
返回指定的数据。如果没有此类数据,则返回空字符串。
dataTransfer.setData(format, data)
所有当前引擎都支持。
添加指定的数据。
dataTransfer.clearData([ format ])
所有当前引擎都支持。
删除指定格式的数据。如果省略参数,则删除所有数据。
dataTransfer.files
所有当前引擎都支持。
返回一个 FileList
,其中包含正在拖动的文件(如果有)。
作为 拖放事件的一部分创建的 DataTransfer
对象仅在这些事件触发时有效。
一个 DataTransfer
对象与其 拖动数据存储 关联,前提是它有效。
一个 DataTransfer
对象具有关联的 类型数组,它是一个 FrozenArray<DOMString>
,最初为空。当 DataTransfer
对象的 拖动数据存储项列表 内容发生更改或 DataTransfer
对象不再与 拖动数据存储 关联时,运行以下步骤
令 L 为一个空序列。
如果 DataTransfer
对象仍与 拖动数据存储 关联,则
对于 DataTransfer
对象的 拖动数据存储项列表 中每个 类型 为 text 的项,在 L 中添加一个条目,该条目包含该项的 类型字符串。
如果 DataTransfer
对象的 拖动数据存储项列表 中有任何 类型 为 File 的项,则在 L 中添加一个条目,该条目包含字符串 "Files
"。(此值可以与其他值区分开来,因为它不是小写字母。)
将 DataTransfer
对象的 类型数组 设置为 从 L 创建冻结数组 的结果。
当调用 DataTransfer()
构造函数时,必须返回一个新创建的 DataTransfer
对象,其初始化如下
将 dropEffect
和 effectAllowed
设置为 "none"。
dropEffect
属性控制用户在拖放操作期间获得的拖放反馈。当创建 DataTransfer
对象时,dropEffect
属性设置为字符串值。在获取时,它必须返回其当前值。在设置时,如果新值为 "none
"、"copy
"、"link
" 或 "move
" 之一,则属性的当前值必须设置为新值。其他值必须忽略。
effectAllowed
属性用于拖放处理模型中初始化 dropEffect
属性,在 dragenter
和 dragover
事件期间。当创建 DataTransfer
对象时,effectAllowed
属性设置为字符串值。在获取时,它必须返回其当前值。在设置时,如果 拖动数据存储 的 模式 为 读写模式 且新值为 "none
"、"copy
"、"copyLink
"、"copyMove
"、"link
"、"linkMove
"、"move
"、"all
" 或 "uninitialized
" 之一,则属性的当前值必须设置为新值。否则,它必须保持不变。
items
属性必须返回与 DataTransfer
对象关联的 DataTransferItemList
对象。
setDragImage(image, x, y)
方法必须运行以下步骤
如果 DataTransfer
对象不再与 拖动数据存储 关联,则返回。不会发生任何事情。
如果 image 是一个 img
元素,则将 拖动数据存储位图 设置为该元素的图像(在其 自然大小 处);否则,将 拖动数据存储位图 设置为从给定元素生成的图像(执行此操作的确切机制目前未指定)。
将 拖动数据存储热点坐标 设置为给定的 x、y 坐标。
types
属性必须返回此 DataTransfer
对象的 类型数组。
getData(format)
方法必须运行以下步骤
如果 DataTransfer
对象不再与 拖动数据存储 关联,则返回空字符串。
令 format 为第一个参数,转换为 ASCII 小写字母。
令 convert-to-URL 为 false。
如果 format 等于 "text
",则将其更改为 "text/plain
"。
如果 format 等于 "url
",则将其更改为 "text/uri-list
" 并将 convert-to-URL 设置为 true。
令 result 为 拖放数据存储项列表 中 类型 为 Plain Unicode string 且 类型字符串 等于 format 的项的数据。
如果 convert-to-URL 为 true,则根据 text/uri-list
数据对 result 进行解析,然后将 result 设置为列表中的第一个 URL(如果有),否则设置为空字符串。 [RFC2483]
返回 result。
setData(format, data)
方法必须执行以下步骤
如果 DataTransfer
对象不再与 拖放数据存储 关联,则返回。什么也不会发生。
令 format 为第一个参数,转换为 ASCII 小写。
如果 format 等于 "text
",则将其更改为 "text/plain
"。
如果 format 等于 "url
",则将其更改为 "text/uri-list
"。
向 拖放数据存储项列表 添加一个 类型 为 text、类型字符串 等于 format 且数据为方法的第二个参数给定的字符串的项。
clearData(format)
方法必须执行以下步骤
如果 DataTransfer
对象不再与 拖放数据存储 关联,则返回。什么也不会发生。
如果该方法在没有参数的情况下被调用,则删除 拖放数据存储项列表 中每个 类型 为 Plain Unicode string 的项,并返回。
将 format 设置为 format,转换为 ASCII 小写。
如果 format 等于 "text
",则将其更改为 "text/plain
"。
如果 format 等于 "url
",则将其更改为 "text/uri-list
"。
clearData()
方法不影响拖动过程中是否包含任何文件,因此 types
属性的列表在调用 clearData()
后可能仍然不为空(如果拖动过程中包含任何文件,它仍然包含 "Files
" 字符串)。
files
属性必须返回一个 动态 的 FileList
序列,该序列由表示通过以下步骤找到的文件的 File
对象组成。此外,对于给定的 FileList
对象和给定的底层文件,每次都必须使用相同的 File
对象。
以一个空列表 L 开始。
如果 DataTransfer
对象不再与 拖放数据存储 关联,则 FileList
为空。返回空列表 L。
对于 拖放数据存储项列表 中每个 类型 为 File 的项,将该项的数据(特别是文件的文件名和内容,以及其 类型)添加到列表 L 中。
通过这些步骤找到的文件是列表 L 中的文件。
此版本的 API 在拖动过程中不公开文件的类型。
DataTransferItemList
接口所有当前引擎都支持。
每个 DataTransfer
对象都与一个 DataTransferItemList
对象关联。
[Exposed =Window ]
interface DataTransferItemList {
readonly attribute unsigned long length ;
getter DataTransferItem (unsigned long index );
DataTransferItem ? add (DOMString data , DOMString type );
DataTransferItem ? add (File data );
undefined remove (unsigned long index );
undefined clear ();
};
items.length
所有当前引擎都支持。
返回 拖放数据存储 中的项目数。
items[index]
返回表示 拖放数据存储 中第 index 个条目的 DataTransferItem
对象。
items.remove(index)
所有当前引擎都支持。
删除 拖放数据存储 中的第 index 个条目。
items.clear()
所有当前引擎都支持。
删除 拖放数据存储 中的所有条目。
items.add(data)
所有当前引擎都支持。
items.add(data, type)
为给定数据向 拖放数据存储 添加一个新条目。如果数据是纯文本,则还必须提供 type 字符串。
当 DataTransferItemList
对象的 DataTransfer
对象与 拖放数据存储 关联时,DataTransferItemList
对象的模式与 拖放数据存储模式 相同。当 DataTransferItemList
对象的 DataTransfer
对象不与 拖放数据存储 关联时,DataTransferItemList
对象的模式为禁用模式。本节中引用的 拖放数据存储(仅在 DataTransferItemList
对象不处于禁用模式时使用)是 DataTransferItemList
对象的 DataTransfer
对象关联的 拖放数据存储。
如果对象处于禁用模式,则 length
属性必须返回零;否则,它必须返回 拖放数据存储项列表 中的项目数。
当 DataTransferItemList
对象不处于禁用模式时,其 支持的属性索引 是 拖放数据存储项列表 的 索引。
要 确定 DataTransferItemList
对象的索引属性 i 的值,用户代理必须返回一个表示 拖放数据存储 中第 i 个项目的 DataTransferItem
对象。每次从该 DataTransferItemList
对象获取特定项目时,都必须返回相同的对象。当 DataTransferItem
对象首次创建时,它必须与与 DataTransferItemList
对象相同的 DataTransfer
对象关联。
add()
方法必须执行以下步骤
如果 DataTransferItemList
对象不处于 读写模式,则返回 null。
跳转到以下列表中的适当步骤集
如果 拖放数据存储项列表 中已存在一个 类型 为 text 且 类型字符串 等于该方法第二个参数值(转换为 ASCII 小写)的项,则抛出一个 "NotSupportedError
" DOMException
。
否则,向 拖放数据存储项列表 添加一个项,该项的 类型 为 text,类型字符串 等于该方法第二个参数值(转换为 ASCII 小写),其数据为该方法第一个参数给出的字符串。
File
向 拖放数据存储项列表 添加一个项,该项的 类型 为 File,类型字符串 为 类型
的 File
(转换为 ASCII 小写),其数据与 File
的数据相同。
确定与新添加的项相对应的索引属性的值,并返回该值(一个新创建的 DataTransferItem
对象)。
remove(index)
方法必须运行以下步骤
如果 DataTransferItemList
对象不在 读写模式 下,则抛出一个 "InvalidStateError
" DOMException
。
如果 拖放数据存储 不包含第 index 个项,则返回。
从 拖放数据存储 中删除第 index 个项。
clear()
方法,如果 DataTransferItemList
对象处于 读写模式 下,则必须从 拖放数据存储 中删除所有项。否则,它必须什么也不做。
DataTransferItem
接口所有当前引擎都支持。
每个 DataTransferItem
对象都与一个 DataTransfer
对象相关联。
[Exposed =Window ]
interface DataTransferItem {
readonly attribute DOMString kind ;
readonly attribute DOMString type ;
undefined getAsString (FunctionStringCallback ? _callback );
File ? getAsFile ();
};
callback FunctionStringCallback = undefined (DOMString data );
item.kind
所有当前引擎都支持。
返回 拖放数据项类型,其中之一:"string"、"file"。
item.type
所有当前引擎都支持。
返回 拖放数据项类型字符串。
item.getAsString(callback)
所有当前引擎都支持。
如果 拖放数据项类型 为 text,则使用字符串数据作为参数调用回调函数。
file = item.getAsFile()
所有当前引擎都支持。
当 DataTransferItem
对象的 DataTransfer
对象与 拖放数据存储 相关联,并且该 拖放数据存储 的 拖放数据存储项列表 仍然包含 DataTransferItem
对象表示的项时,DataTransferItem
对象的 模式 与 拖放数据存储模式 相同。当 DataTransferItem
对象的 DataTransfer
对象 *不* 与 拖放数据存储 相关联,或者如果 DataTransferItem
对象表示的项已从相关的 拖放数据存储项列表 中删除,则 DataTransferItem
对象的 模式 为 禁用模式。本节中引用的 拖放数据存储(仅在 DataTransferItem
对象不处于 禁用模式 下时使用)是与 DataTransferItem
对象的 DataTransfer
对象相关联的 拖放数据存储。
kind
属性必须返回空字符串,如果 DataTransferItem
对象处于 禁用模式 下;否则,它必须返回下表中第二列中给出的字符串,该字符串来自第一列中包含 DataTransferItem
对象表示的项的 拖放数据项类型 的行的单元格。
类型 | 字符串 |
---|---|
文本 | "string " |
文件 | "file " |
type
属性必须返回空字符串,如果 DataTransferItem
对象处于 禁用模式 下;否则,它必须返回 DataTransferItem
对象表示的项的 拖放数据项类型字符串。
getAsString(callback)
方法必须运行以下步骤
如果 callback 为 null,则返回。
如果 DataTransferItem
对象不处于 读写模式 或 只读模式 下,则返回。回调函数永远不会被调用。
如果 拖放数据项类型 不是 text,则返回。回调函数永远不会被调用。
否则,将一个任务排队 以调用 callback,并将 DataTransferItem
对象表示的项的实际数据作为参数传递。
getAsFile()
方法必须运行以下步骤
如果 DataTransferItem
对象不处于 读写模式 或 只读模式 下,则返回 null。
如果 拖放数据项类型 不是 File,则返回 null。
返回一个新的 File
对象,表示 DataTransferItem
对象表示的项的实际数据。
DragEvent
接口所有当前引擎都支持。
所有当前引擎都支持。
拖放处理模型涉及多个事件。它们都使用 DragEvent
接口。
[Exposed =Window ]
interface DragEvent : MouseEvent {
constructor (DOMString type , optional DragEventInit eventInitDict = {});
readonly attribute DataTransfer ? dataTransfer ;
};
dictionary DragEventInit : MouseEventInit {
DataTransfer ? dataTransfer = null ;
};
event.dataTransfer
所有当前引擎都支持。
返回事件的 DataTransfer
对象。
尽管为了与其他事件接口保持一致,DragEvent
接口有一个构造函数,但它并不是特别有用。特别是,无法从脚本创建有用的 DataTransfer
对象,因为 DataTransfer
对象具有由浏览器在拖放过程中协调的处理和安全模型。
DragEvent
接口的 dataTransfer
属性必须返回其初始化的值。它表示事件的上下文信息。
当用户代理需要在元素上 触发名为 e 的 DND 事件 时,使用特定的 拖放数据存储,并可选地使用特定的 相关目标,用户代理必须运行以下步骤
如果没有提供特定的 相关目标,则将 相关目标 设置为 null。
如果 e 是 dragstart
,则将 拖放数据存储模式 设置为 读写模式,并将 dataDragStoreWasChanged 设置为 true。
令 dataTransfer 为一个新创建的与给定 拖放数据存储 关联的 DataTransfer
对象。
将 effectAllowed
属性设置为 拖放数据存储 的 拖放数据存储允许的效果状态。
如果 e 是 dragstart
、drag
或 dragleave
,则将 dropEffect
属性设置为 “none
”;如果 e 是 drop
或 dragend
,则将其设置为与 当前拖放操作 对应的值;否则(即,如果 e 是 dragenter
或 dragover
),则将其设置为基于 effectAllowed
属性的值和拖放源的值,如下表所示。
effectAllowed | dropEffect |
---|---|
"none " | "none " |
"copy " | "copy " |
"copyLink " | "copy ",或者,如果合适,则为 “link ” |
"copyMove " | "copy ",或者,如果合适,则为 “move ” |
"all " | "copy ",或者,如果合适,则为 “link ” 或 “move ” |
"link " | "link " |
"linkMove " | "link ",或者,如果合适,则为 “move ” |
"move " | "move " |
当拖动的是文本控件中的选择内容时,uninitialized | "move ",或者,如果合适,则为 “copy ” 或 “link ” |
当拖动的是选择内容时,uninitialized | "copy ",或者,如果合适,则为 “link ” 或 “move ” |
当拖动的是具有 href 属性的 a 元素时,uninitialized | "link ",或者,如果合适,则为 “copy ” 或 “move ” |
任何其他情况 | "copy ",或者,如果合适,则为 “link ” 或 “move ” |
如果上表提供了 可能合适的替代方案,则用户代理可以在平台约定指示用户已请求这些替代效果的情况下,使用列出的替代值。
例如,Windows 平台约定规定,按住“Alt”键拖动表示用户希望链接数据,而不是移动或复制数据。因此,在 Windows 系统上,如果上表中“link
” 是一个选项,并且同时按下“Alt”键,则用户代理可以选择该选项,而不是 “copy
” 或 “move
”。
将 event 的 type
属性初始化为 e,其 bubbles
属性初始化为 true,其 view
属性初始化为 window,其 relatedTarget
属性初始化为 相关目标,其 dataTransfer
属性初始化为 dataTransfer。
如果 e 不是 dragleave
或 dragend
,则将 event 的 cancelable
属性初始化为 true。
根据输入设备的状态(如同用户交互事件一样)初始化 event 的鼠标和键盘属性。
如果没有相关的指向设备,则将 event 的 screenX
、screenY
、clientX
、clientY
和 button
属性初始化为 0。
在指定的目标元素上 分派 event。
将 拖放数据存储允许的效果状态 设置为 dataTransfer 的 effectAllowed
属性的当前值。(只有当 e 是 dragstart
时,它才能更改值。)
断开 dataTransfer 与 拖放数据存储 之间的关联。
当用户尝试开始拖放操作时,用户代理必须运行以下步骤。即使拖放实际上是在另一个文档或应用程序中开始的,并且用户代理直到它与用户代理管辖范围内的文档相交时才意识到拖放正在发生,用户代理也必须像运行这些步骤一样进行操作。
确定正在拖动的内容,如下所示
如果拖放操作是在选择内容上调用的,则正在拖动的是选择内容。
否则,如果拖放操作是在 Document
上调用的,则它是从用户尝试拖动的节点开始,向上遍历祖先链的第一个具有 IDL 属性 draggable
设置为 true 的元素。如果没有这样的元素,则没有正在拖动的内容;返回,拖放操作从未开始。
否则,拖放操作是在用户代理的管辖范围之外调用的。正在拖动的内容由拖放开始的文档或应用程序定义。
确定哪个 DOM 节点是 源节点,如下所示
如果拖动的是选区,则源节点是用户开始拖动操作的文本
节点(通常是用户最初点击的文本
节点)。如果用户没有指定特定的节点,例如,如果用户只是告诉用户代理开始拖动“选区”,则源节点是包含选区一部分的第一个文本
节点。
否则,如果拖动的是元素,则源节点是被拖动的元素。
否则,源节点是另一个文档或应用程序的一部分。当本规范要求在此情况下在源节点上分发事件时,用户代理必须遵循与该情况相关的平台特定约定。
在拖放操作过程中,会在源节点上触发多个事件。
确定被拖动节点列表,如下所示
如果拖动的是选区,则向拖放数据存储项列表添加一个项,其属性设置如下
text/plain
"否则,如果拖动任何文件,则为每个文件向拖放数据存储项列表添加一个项,其属性设置如下
application/octet-stream
"。目前,拖动文件只能从可导航区域外部进行,例如从文件系统管理器应用程序进行。
如果拖动操作从应用程序外部发起,则用户代理必须根据被拖动数据的类型向拖放数据存储项列表添加项,并在适当情况下遵循平台约定;但是,如果平台约定不使用MIME 类型来标记被拖动的数据,则用户代理必须尽力尝试将类型映射到 MIME 类型,并且在任何情况下,所有拖放数据项类型字符串都必须转换为 ASCII 小写。
用户代理还可以添加一个或多个表示选区或被拖动元素的其他形式的项,例如 HTML。
如果被拖动节点列表不为空,则将这些节点的微数据提取为 JSON 格式,并向拖放数据存储项列表添加一个项,其属性设置如下
application/microdata+json
运行以下子步骤
令urls为« »。
对于被拖动节点列表中的每个node
href
属性的a
元素href
内容属性的值(相对于元素的节点文档)编码、解析和序列化 URL的结果添加到urls中。src
属性的img
元素src
内容属性的值(相对于元素的节点文档)编码、解析和序列化 URL的结果添加到urls中。如果urls仍然为空,则返回。
令url 字符串为将urls中的字符串按添加顺序连接起来的结果,并用 U+000D 回车 U+000A 换行字符对 (CRLF) 分隔。
向拖放数据存储项列表添加一个项,其属性设置如下
text/uri-list
根据用户代理更新拖放数据存储默认反馈(如果用户正在拖动选区,则选区可能是此反馈的基础;如果用户正在拖动元素,则将使用该元素的渲染;如果拖动从用户代理外部开始,则应使用确定拖动反馈的平台约定)。
如果事件被取消,则不应发生拖放操作;返回。
由于几乎可以肯定没有注册事件监听器的事件永远不会被取消,因此如果作者没有明确阻止,拖放始终可供用户使用。
在源节点上触发一个名为pointercancel
的指针事件,并根据指针事件的要求触发任何其他后续事件。[POINTEREVENTS]
以与平台约定一致的方式,并如下所述启动拖放操作。
拖放反馈必须从以下第一个可用的来源生成
从用户代理需要启动拖放操作的那一刻起,到拖放操作结束时,必须抑制设备输入事件(例如鼠标和键盘事件)。
在拖动操作期间,用户直接指示为放置目标的元素称为直接用户选择。(只有元素才能被用户选择;其他节点不得作为放置目标提供。)但是,直接用户选择不一定是当前目标元素,后者是当前为拖放操作的放置部分选择的元素。
当用户选择不同的元素时(通过指向它们或以其他方式选择它们),直接用户选择会发生变化。根据文档中事件监听器的结果,当前目标元素会在直接用户选择发生变化时发生变化,如下所述。
当前目标元素和直接用户选择都可以为 null,这意味着没有选择目标元素。它们也可以都是其他(基于 DOM 的)文档或其他(非 Web)程序中的元素。(例如,用户可以将文本拖动到文字处理器中。)当前目标元素最初为 null。
此外,还有一个当前拖动操作,它可以取值“none
”、“copy
”、“link
”和“move
”。最初,它的值为“none
”。它会根据以下步骤中的描述由用户代理更新。
用户代理必须在拖动操作启动后以及此后只要拖动操作正在进行,每 350 毫秒 (±200 毫秒) 就排队执行一个任务,以按顺序执行以下步骤
如果当下一个迭代到期时,用户代理仍在执行序列的先前迭代(如果有),则对于此迭代返回(有效地“跳过拖放操作的错过的帧”)。
在源节点上触发一个名为drag
的 DND 事件。如果此事件被取消,则用户代理必须将当前拖动操作设置为“none
”(没有拖动操作)。
如果drag
事件未被取消且用户未结束拖放操作,则检查拖放操作的状态,如下所示
如果用户的当前选中项与上一次迭代期间的选中项不同(或者如果这是第一次迭代),并且当前选中项与当前目标元素不同,则按如下方式更新当前目标元素。
也将当前目标元素设置为 null。
将当前目标元素设置为当前选中项。
在当前选中项上触发名为 dragenter
的 DND 事件。
如果事件被取消,则将当前目标元素设置为当前选中项。
否则,从以下列表中运行相应的步骤
如果上一步导致当前目标元素发生更改,并且上一个目标元素不是 null 或非 DOM 文档的一部分,则在先前目标元素上触发名为 dragleave
的 DND 事件,并将新的当前目标元素作为特定的 相关目标。
如果当前目标元素是 DOM 元素,则在此当前目标元素上触发名为 dragover
的 DND 事件。
如果 dragover
事件未被取消,则从以下列表中运行相应的步骤
textarea
,或 input
元素,其 type
属性处于 文本 状态)或编辑宿主或可编辑元素,并且拖动数据存储项列表中有一个项目,其拖动数据项类型字符串为 "text/plain
" 且拖动数据项类型为 text将当前拖动操作重置为 "none
"。
否则(如果 dragover
事件被取消),则根据 effectAllowed
和 dropEffect
属性的值设置当前拖动操作,这些属性属于 DragEvent
对象的 dataTransfer
对象,其状态是在事件 分派 完成后,如下表所示
effectAllowed | dropEffect | 拖动操作 |
---|---|---|
"uninitialized ","copy ","copyLink ","copyMove " 或 "all " | "copy " | "copy " |
"uninitialized ","link ","copyLink ","linkMove " 或 "all " | "link " | "link " |
"uninitialized ","move ","copyMove ","linkMove " 或 "all " | "move " | "move " |
任何其他情况 | "none " |
否则,如果当前目标元素不是 DOM 元素,则使用特定于平台的机制来确定正在执行的拖动操作(无、复制、链接或移动),并相应地设置当前拖动操作。
更新拖动反馈(例如鼠标光标),以匹配当前拖动操作,如下所示
拖动操作 | 反馈 |
---|---|
"copy " | 如果在此处放下,则数据将被复制。 |
"link " | 如果在此处放下,则数据将被链接。 |
"move " | 如果在此处放下,则数据将被移动。 |
"none " | 不允许任何操作,在此处放下将取消拖放操作。 |
否则,如果用户结束了拖放操作(例如,在鼠标驱动的拖放界面中释放鼠标按钮),或者 drag
事件被取消,则这将是最后一次迭代。运行以下步骤,然后停止拖放操作
如果当前拖动操作为 "none
"(无拖动操作),或者如果用户通过取消操作结束了拖放操作(例如,按 Escape 键),或者如果当前目标元素为 null,则拖动操作失败。运行这些子步骤
令 dropped 为 false。
如果当前目标元素是 DOM 元素,则在该元素上触发名为 dragleave
的 DND 事件;否则,如果它不是 null,则使用特定于平台的约定来取消拖动。
将当前拖动操作设置为 "none
"。
否则,拖动操作可能成功;运行这些子步骤
令 dropped 为 true。
如果当前目标元素是 DOM 元素,则在该元素上触发名为 drop
的 DND 事件;否则,使用特定于平台的约定来指示放下。
如果事件被取消,则将当前拖动操作设置为dropEffect
属性的值,该属性属于DragEvent
对象的dataTransfer
对象,其状态为事件分发完成后所处的状态。
否则,事件未被取消;执行事件的默认操作,具体取决于确切的目标,如下所示
textarea
,或input
元素,其type
属性处于文本状态)或编辑宿主或可编辑元素,并且拖动数据存储项列表中有一个项目,其拖动数据项类型字符串为"text/plain
",并且拖动数据项类型为text将拖动数据存储项列表中第一个项目的实际数据插入到文本控件或编辑宿主或可编辑元素中,使其拖动数据项类型字符串为"text/plain
",并且拖动数据项类型为text,方式应与平台特定的约定一致(例如,将其插入到当前鼠标光标位置,或将其插入到字段末尾)。
作为dragend
事件的默认操作,运行以下列表中的相应步骤
move
",并且拖放操作的源是DOM中的一个选择,该选择完全包含在编辑宿主中move
",并且拖放操作的源是文本控件中的一个选择用户代理应从相关的文本控件中删除拖动的选择。
none
"拖动被取消。如果平台约定规定需要向用户显示此操作(例如,通过动画显示拖动的选择回到拖放操作的源),则执行此操作。
该事件没有默认操作。
在本步骤中,文本控件是指textarea
元素或input
元素,其type
属性处于文本、搜索、电话、URL、电子邮件、密码或数字状态之一。
鼓励用户代理考虑如何在可滚动区域边缘附近对拖动做出反应。例如,如果用户将链接拖到长页面上视口的底部,则可能需要滚动页面,以便用户可以将链接放到页面上的更下方。
此模型独立于所涉及节点来自哪个Document
对象;事件按上述方式触发,并且处理模型的其余部分按上述方式运行,无论操作涉及多少个文档。
本节是非规范性的。
以下事件参与拖放模型。
事件名称 | 目标 | 可取消? | 拖动数据存储模式 | dropEffect | 默认操作 |
---|---|---|---|---|---|
dragstart 所有当前引擎都支持。 Firefox9+Safari3.1+Chrome1+ Opera12+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12+ | 源节点 | ✓ 可取消 | 读写模式 | "none " | 启动拖放操作 |
drag 所有当前引擎都支持。 Firefox9+Safari3.1+Chrome1+ Opera12+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12+ | 源节点 | ✓ 可取消 | 保护模式 | "none " | 继续拖放操作 |
dragenter 所有当前引擎都支持。 Firefox9+Safari3.1+Chrome1+ Opera12+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12+ | 立即用户选择或body元素 | ✓ 可取消 | 保护模式 | 基于effectAllowed 值 | 拒绝立即用户选择作为潜在的目标元素 |
dragleave 所有当前引擎都支持。 Firefox9+Safari3.1+Chrome1+ Opera12+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12+ | 上一个目标元素 | — | 保护模式 | "none " | 无 |
dragover 所有当前引擎都支持。 Firefox9+Safari3.1+Chrome1+ Opera12+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12+ | 当前目标元素 | ✓ 可取消 | 保护模式 | 基于effectAllowed 值 | 将当前拖动操作重置为“none” |
drop 所有当前引擎都支持。 Firefox9+Safari3.1+Chrome1+ Opera12+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12+ | 当前目标元素 | ✓ 可取消 | 只读模式 | 当前拖动操作 | 变化 |
dragend 所有当前引擎都支持。 Firefox9+Safari3.1+Chrome1+ Opera12+Edge79+ Edge (Legacy)12+Internet Explorer9+ Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android12+ | 源节点 | — | 保护模式 | 当前拖动操作 | 变化 |
所有这些事件都冒泡并组成,并且effectAllowed
属性始终具有dragstart
事件之后的值,在dragstart
事件中默认为"uninitialized
"。
draggable
属性所有当前引擎都支持。
所有HTML元素都可以设置draggable
内容属性。draggable
属性是一个枚举属性,具有以下关键字和状态
关键字 | 状态 | 简要说明 |
---|---|---|
true
| true | 该元素可拖动。 |
false
| false | 该元素不可拖动。 |
属性的缺失值默认值和无效值默认值均为auto状态。auto状态使用用户代理的默认行为。
具有draggable
属性的元素也应具有title
属性,用于非视觉交互的目的,为该元素命名。
element.draggable [ = value ]
如果元素可拖动,则返回true;否则,返回false。
可以设置,以覆盖默认值并设置draggable
内容属性。
draggable
IDL属性的值取决于内容属性的方式(如下所述),它控制元素是否可拖动。通常,只有文本选择可拖动,但其draggable
IDL属性为true的元素也会变得可拖动。
如果元素的draggable
内容属性处于true状态,则draggable
IDL属性必须返回true。
否则,如果元素的draggable
内容属性处于false状态,则draggable
IDL属性必须返回false。
否则,元素的draggable
内容属性处于auto状态。如果元素是img
元素、object
元素(表示图像)或a
元素(具有href
内容属性),则draggable
IDL属性必须返回true;否则,draggable
IDL属性必须返回false。
如果 draggable
IDL 属性设置为 false,则 draggable
内容属性必须设置为字面值 "false
"。如果 draggable
IDL 属性设置为 true,则 draggable
内容属性必须设置为字面值 "true
"。
用户代理在 dragstart
事件期间添加到 DataTransfer
对象中的数据,在 drop
事件发生之前,不得使其对脚本可用。否则,如果用户将敏感信息从一个文档拖放到第二个文档,并在过程中经过一个恶意第三方文档,则恶意文档可能会拦截这些数据。
出于同样的原因,用户代理必须仅在用户明确结束拖动操作时才认为拖放操作成功——如果任何脚本结束拖动操作,则必须将其视为不成功(取消),并且 drop
事件不得触发。
用户代理应注意不要响应脚本操作开始拖放操作。例如,在鼠标和窗口环境中,如果脚本在用户按下鼠标按钮时移动窗口,则用户代理不会将其视为开始拖动。这一点很重要,因为否则用户代理可能会在未经用户同意的情况下,导致数据从敏感源拖动并放到恶意文档中。
用户代理在拖动和放置内容时,应使用已知安全功能的安全列表过滤潜在的活动(脚本)内容(例如 HTML)。类似地,相对 URL 应转换为绝对 URL,以避免引用以意外方式更改。本规范未指定如何执行此操作。
假设一个恶意页面提供一些内容,并让用户选择并拖放(或者实际上是复制粘贴)这些内容到受害者页面的 contenteditable
区域。如果浏览器不确保仅拖放安全内容,则选择中的潜在不安全内容(如脚本和事件处理程序)一旦拖放到(或粘贴到)受害者站点,就会获得受害者站点的权限。这将使跨站点脚本攻击成为可能。