Warning:
This wiki has been archived and is now read-only.

HTML5/dnd

From HTML5 Chinese Interest Group Wiki
Jump to: navigation, search

拖放

本节定义了一种基于事件的拖放机制。

本规范并不精确地规定什么是实际的拖放操作。

在拥有定点设备的视觉媒体上,拖拽操作可以默认地定义为鼠标点下事件以及一系列后续的鼠标移动事件,释放操作可以释放鼠标触发。

在使用定点设备之外的输入形式时,用户可能必须要明确的表明他们执行拖放操作的意图,说明他们想要拖动什么、在什么地方释放。

无论如何实现,拖放操作必须拥有一个起始点(例如,鼠标在何处点击、选择的起始点或者被选为拖拽对象的元素),可以拥有任意数目的中间步骤(拖拽期间鼠标滑过的元素、用户在备选元素之间选择的可能的释放点),以及必选的一个结束点(释放鼠标按钮时所在的元素、或者最终选定的元素)或者取消。结束点必须为释放前最后选定的作为可能的释放点的元素(所以如果操作没有被取消,则其必须至少为中间步骤中的一个元素)。

介绍

本节不具规范性

很容易让一个元素可以被拖放:给元素设置一个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”指示数据将被移动)。

注:作为dropzone属性的替代,释放目标可以处理dragenter事件(来表示释放目标是否允许释放)以及dragover事件(来指定应该向用户展示何种反馈)。

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>

拖动数据储存

构成拖放操作的数据被称为拖动数据存储,其包含下列信息:

  • 一个拖动数据存储元素列表,其为一个表示拖动数据的元素的列表,其中的每个元素包含下列信息:
    • 拖动数据元素种类
      • 数据的种类:
        • 纯Unicode字符串
          • 文本。
        • 文件
          • 拥有一个文件名的二进制数据。
    • 拖动数据元素类型字符串
    • 真实数据
      • 根据拖动数据元素种类,一个Unicode或二进制字符串,在某些情况下还包括一个文件名(为Unicode字符串)。
  • 下列信息用于在拖动中产生UI反馈:
    • 用户代理定义的默认反馈信息,被称为拖动数据存储默认反馈
    • 零或多个元素的列表,被称为拖动数据存储元素列表
    • 可选的,一个位图图片以及图片中一个点的坐标,被称为拖动数据存储图片拖动数据存储热点坐标
  • 一个拖动数据存储模式,其为下列值之一:
    • 读写模式
    • 只读模式
      • 对应drop事件。表示被拖动数据的元素列表,包括数据,可以读取。不可以插入新数据。
    • 受保护模式
      • 对应所以事件。可以枚举表示拖动数据的元素的拖动数据存储列表中的格式及种类,但是数据本身不可用且不可以插入新数据。
  • 一个拖动数据存储允许的效果状态,且为一个字符串。

创建一个拖动数据存储时,其必须初始化其拖动数据存储元素列表为空、没有拖动数据存储默认反馈、其拖动数据存储元素列表为空、没有拖动数据存储位图/拖动数据存储热点坐标、其拖动数据存储模式受保护模式、且其拖动数据存储允许的效果状态为字符串“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属性在拖放过程模式中用于在dragenterdragover事件过程中初始化dropEffect属性。在创建DataTransfer对象时,effectAllowed属性被设为一个字符串值。在获取时,其必须返回其当前值。在设置时,如果新值为“none”、“copy”、“copyLink”、“copyMove”、“link”、“linkMove”、“move”、“all”或“uninitialized”之一,则属性的当前值必须被设为新值。必须忽略其他值。

items属性必须返回一个与DataTransfer对象相关联的DataTransferItemList对象。必须每次返回同一个对象。

setDragImage(element, x, y)方法必须执行下列步骤:

  1. 如果DataTransfer对象没有与一个拖拽数据存储相关联,则跳过这些步骤。不发生任何事情。
  2. 如果拖拽数据存储模式不是读写模式,则跳过这些步骤。不发生任何事情。
  3. 如果element参数为一个img元素,则设拖拽数据存储位图为该元素的图片(保留其原图大小);否则,设拖拽数据存储位图为由给出的元素所产生的图片(详细的工作机制不做指定)。
  4. 拖拽数据存储热点坐标为给出的xy坐标。

addElement(element)方法是指定用户代理如何渲染拖拽反馈的一种替代方式。该方法必须执行下列步骤:

  1. 如果DataTransfer对象没有与一个拖拽数据存储相关联,则跳过这些步骤。不发生任何事情。
  2. 如果拖拽数据存储模式不是读写模式,则跳过这些步骤。不发生任何事情。
  3. 将给出的element插入到元素的拖拽数据存储元素列表之中。
注:setDragImage()addElement()之间的区别为后者能够基于元素的当前渲染自动生成图片(可能会在拖拽过程中持续更新,例如,如果元素包含一个正在播放的视频),而前者在方法被调用的时候使用一个精确指定的图片。

types属性必须返回一个活跃的DOMStringList,其中给出下列步骤产生的字符串。每次返回的必须是同一个对象。

  1. 从空列表L开始。
  2. 如果DataTransfer对象没有与一个拖拽数据存储相关联,则DOMStringList为空。跳过这些步骤;返回空列表L
  3. 对于拖拽数据存储项列表类型纯Unicode文本的每一项,向列表L添加一个包含项目的类型字符串的实体。
  4. 如果拖拽数据存储项列表存在类型File的项目,则向列表L添加一个包含字符串“Files”的实体。(因为该字符串不是小写形式,所以它可以与其他值区分。)
  5. 这些步骤所产生的字符串在列表L中。

getData(format)方法必须执行下列步骤:

  1. 如果DataTransfer对象没有与一个拖拽数据存储相关联,则返回空字符串并跳过这些步骤。
  2. 如果拖拽数据存储模式受保护模式,则返回空字符串并跳过这些步骤。
  3. 格式为第一个参数,并转换为ASCII小写形式
  4. 转换为URL为假。
  5. 如果格式等于“text”,则将其改为“text/plain”。
  6. 如果格式等于“url”,则将其改为“text/uri-list”。
  7. 如果拖拽数据存储项列表中不存在类型纯Unicode文本类型字符串等于格式的项目,则返回空字符串并跳过这些步骤。
  8. 结果拖拽数据存储项列表类型纯Unicode文本类型字符串等于格式的项目的数据。
  9. 如果转换为URL为真,则将结果按照text/uri-list数据解析,并且设结果为列表中的第一个URL(如果存在),或者空字符串。[RFC2483]
  10. 返回结果

setData(format, data)方法必须执行下列步骤:

  1. 如果DataTransfer对象没有与一个拖拽数据存储相关联,则跳过这些步骤。不发生任何事情。
  2. 如果拖拽数据存储模式不是读写模式,则跳过这些步骤。不发生任何事情。
  3. 格式为第一个参数,并转换为ASCII小写形式
  4. 如果格式等于“text”,则将其改为“text/plain”。
    如果格式等于“url”,则将其改为“text/uri-list”。
  5. 移除拖拽数据存储项列表类型纯Unicode文本类型字符串等于格式的项目。
  6. 拖拽数据存储项列表中添加一个项目,其类型纯Unicode文本类型字符串等于格式且数据为方法的第二个参数给出的字符串。

clearData()方法必须执行下列步骤:

  1. 如果DataTransfer对象没有与一个拖拽数据存储相关联,则跳过这些步骤。不发生任何事情。
  2. 如果拖拽数据存储模式不是读写模式,则跳过这些步骤。不发生任何事情。
  3. 如果调用方法时没有参数,则移除拖拽数据存储项列表类型纯Unicode文本的所有项目,并跳过这些步骤。
  4. 格式为第一个参数,并转换为ASCII小写形式
  5. 如果格式等于“text”,则将其改为“text/plain”。
    如果格式等于“url”,则将其改为“text/uri-list”。
  6. 移除拖拽数据存储项列表类型纯Unicode文本类型字符串等于格式的项目。
注:clearData()方法不影响是否有文件被包含在拖拽中,所以在调用clearData()方法之后types属性的列表可能仍然不为空(如果拖拽中存在任意文件,则其仍然包含字符串“Files”)

files属性必须返回一个活跃的包含表示下列步骤所找出的文件的文件对象的FileList序列。每次必须返回同一个对象。另外,对于一个给出的FileList对象和一个给出的隐含文件,必须每次都返回同一个FileList对象。

  1. 从一个空列表L开始。
  2. 如果DataTransfer对象没有与一个拖拽数据存储相关联,则FileList为空。跳过这些步骤;返回空列表L
  3. 如果拖拽数据存储模式受保护模式,则跳过这些步骤;返回空列表L
  4. 对于拖拽数据存储项列表类型File的每一项,向列表L添加该项目数据(文件,特别是它的名称和内容,以及它的类型)。
  5. 这些步骤找到的文件在列表L中。
注:此版本的API不暴露拖拽过程中的文件类型。
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,用户代理必须执行下列步骤:

  1. 如果DataTransferItemList对象没有处于读写模式,则抛出一个InvalidStateError异常并终止这些步骤。
  2. 拖拽数据存储中删除第i个项目。

如果DataTransferItemList对象处于读写模式,则clear方法必须从拖拽数据存储中删除所有项目。否则必须不进行任何操作。

add()方法必须执行下列步骤:

  1. 如果DataTransferItemList对象没有处于读写模式,则返回空并终止这些步骤。
  2. 跳转到下面的列表中适当的步骤:
  3. 决定新添加的项目的索引属性的值,并且返回该值(一个新的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()

如果拖拽数据项类型File,则返回一个File对象。

DataTransferItem对象的DataTransfer对象与一个拖拽数据存储相关,且该拖拽数据存储拖拽数据存储项列表仍然包含DataTransferItem对象表示的项目,则DataTransferItem对象的模式拖拽数据存储模式相同。若DataTransferItem对象的DataTransfer对象没有与一个拖拽数据存储相关联,或者如果DataTransferItem对象所表示的项目已经从相关的拖拽数据存储列表中移除,则DataTransferItem对象的模式不可用模式。本节中对拖拽数据存储的引用(仅用于当DataTransferItem对象不为不可用模式时)为与DataTransferItem对象的DataTransfer对象相关联的拖拽数据存储

如果DataTransferItem对象处于不可以模式,则kind属性必须返回空字符串;否则必须返回返回下表中第一列包含DataTransferItem对象所表示的项目的拖拽数据项类型的行的第二列单元格中的字符串。

类型 字符串
纯Unicode字符串 “string”
File “file”

如果DataTransferItem对象处于不可以模式,则type属性必须返回空字符串;否则必须返回DataTransferItem对象所表示的拖拽数据项类型字符串

getAsString(callback)方法必须执行下列步骤:

  1. 如果callback为空,则跳过这些步骤。
  2. 如果DataTransferItem对象没有处于读写模式只读模式,则跳过这些步骤。不调用回调函数。
  3. 如果拖拽数据项类型不是纯Unicode字符串,则跳过这些步骤。不调用回调函数。
  4. 否则,排入一个任务来调用callback,使用DataTransferItem对象所表示的项目的实际数据作为参数。

getAsFile()方法必须执行下列步骤:

  1. 如果DataTransferItem对象没有处于读写模式只读模式,则返回空并跳过这些步骤。
  2. 如果拖拽数据项类型不是File,则返回空并跳过这些步骤。
  3. 返回一个新的File对象,该对象表示DataTransferItem对象所表示的项目的实际数据。

DragEvent接口

拖放过程模式包含多个事件。它们都使用DragEvent接口。

 [Constructor(DOMString type, optional DragEventInit eventInitDict)]
 interface DragEvent : MouseEvent {
   readonly attribute DataTransfer? dataTransfer;
 };
 
 dictionary DragEventInit : MouseEventInit {
   DataTransfer? dataTransfer;
 };
此区块中不是标准描述,实现要求在下面给出。

event . dataTransfer

返回该事件的DataTransfer对象。

DragEvent接口的dataTransfer属性必须返回其预置的值。在对象创建时,该属性必须被预置为空。其表示事件的上下文信息。

在用户代理需要在一个元素上触发一个名为e的拖放事件时,使用一个特定的拖拽数据存储,用户代理必须执行下列步骤:

  1. 如果edragstart,设拖拽数据存储模式读写模式
    如果edrop,设拖拽数据存储模式只读模式
  2. dataTransfer为一个新创建的DataTransfer对象,其关联至给出的拖拽数据存储
  3. effectAllowed属性为拖拽数据存储拖拽数据存储允许的效果状态
  4. 如果edragstartdragdragleave,则设dropEffect属性为“none”;如果e#event-dropdragend,则设其为相应的当前拖拽操作;否则,其值根据effectAllowed属性的值和拖拽源,根据下表得出(例如,如果edragenterdragover):
  5. 创建一个DragEvent对象,并将其初始化为拥有给定的名称e、冒泡、如果e不是dragleavedragend则可撤销、拥有预置为零的detail属性、按照用户交互事件的输入设备预置的鼠标及键盘属性、预置为空的relatedTarget属性、以及预置为dataTransfer(之前创建的DataTransfer对象)的dataTransfer属性。
  6. 将新创建的DragEvent对象指派给指定的目标元素。
  7. 拖拽数据存储允许的效果状态设为dataTransfereffectAllowed属性的当前值]]。
  8. 如果拖拽数据存储模式在第一步中被修改,则将其改回受保护模式
  9. 破坏dataTransfer拖拽数据存储之间的关联。
effectAllowed dropEffect
none none
copy”、“copyLink”、“copyMove”、“all copy
link”、“linkMove link
move move
uninitialized”,当被拖拽的对象为一个文本字段中的选择。 move
uninitialized”,当被拖拽的对象为一个选择。 copy
uninitialized”,当被拖拽的对象为一个拥有href属性的a元素。 link
任何其他情况 copy

拖放过程模式

在用户试图开始拖拽操作时,用户代理必须执行下列步骤。用户代理的操作必须像是这些步骤在运行,即使拖拽操作实际上起始于其他文档或应用,并且,在用户代理范围下,在拖拽操作进入文档之前用户代理不知道发生了拖拽操作。

  1. 确定被拖拽的对象:
    • 如果拖拽操作在一个选择器上调用,则被拖拽的对象为该选择器。
    • 否则,如果拖拽操作在一个Document上调用,则被拖拽的对象为在沿着祖先链从用户试图拖拽的元素开始的第一个IDL属性draggable为真的元素。如果没有这样的元素,则没有被拖拽的对象;跳过这些步骤,拖放操作没有开始。
    • 否则,拖拽操作起始于用户代理范围之外。拖拽的对象有拖拽起始时所作的文档或应用决定。
      注:拥有href属性的img元素和a元素的draggable属性默认为真。
  2. 创建一个拖拽数据存储。所有本节中随后触发的拖放事件必须使用此拖拽数据存储
  3. 确定那个DOM节点为源节点:
    • 如果被拖拽的对象为选择器,则源节点为用户开始拖拽的文本节点(通常为用户最初所点击的文本节点)。如果用户没有指定一个特定的节点,例如如果用户仅仅通知用户代理开始拖拽“这个选择器”,则源节点为第一个包含部分该选择器的文本节点。
    • 否则,如果被拖拽的对象为一个元素,则源节点为被拖拽的元素。
    • 否则,源节点为其他文档或应用的一部分。在本规范要求将一个事件指派给源节点时,用户代理必须遵循关于这种情况的平台特定的约定。
      注:在整个拖放操作中将在源节点上触发多个事件。
  4. 确定拖拽节点的列表
  5. 如果拖拽节点的列表不为空,则从这些节点中提取微数据到一个JSON表单中,并且向拖拽数据存储项列表中插入一个项目,其属性如下:
  6. 执行下列子步骤:
    1. url为一个空的绝对URL列表。
    2. 对于拖拽节点的列表中的每一个节点
      • 如果节点是一个拥有href属性的a元素
        • 将相对于该元素解析该元素的href内容属性的结果插入到url中。
      • 如果节点是一个拥有src属性的img元素
        • 将相对于该元素解析该元素的src内容属性的结果插入到url中。
    3. 如果url仍然为空,则跳过这些子步骤。
    4. url字符串为将url中的字符串连接的结果,按照他们被插入的顺序,以U+000D回车U+000A换行字符对(CRLF)分隔。
    5. 拖拽数据存储项列表插入一个项目,其属性如下:
  7. 如果被拖拽的对象是一个元素,则设拖拽数据存储元素列表仅包含源节点
    否则,反正用户代理适当地更新拖拽数据存储默认反馈(如果用户拖拽选择器,则选择器将很可能以此反馈最为基础;如果拖拽起始于用户代理之外,则平台约定应该使用的拖拽反馈)。
    注:脚本可以使用addElement()方法向被拖拽对象的列表中添加额外的元素。(该列表仅用于渲染拖拽反馈。)
  8. 源节点触发一个拖放事件,其名为dragstart
    如果事件被撤销,则拖放操作应该没有发生;跳过这些步骤。
    注:因为事件没有注册事件监听器,按照定义,如果编码人员没有明确的阻止,不会被撤销,拖放对用户永远可用。
  9. 在于平台约定一直的机制下开始拖放操作
    拖放反馈必须由下列第一个可用的源产生:
    1. 拖拽数据存储位图(如果存在)。在此情况下,拖拽数据存储热点坐标应当用作规定放置光标时相对与图片的位置。该值按照CSS像素从图片的左边和上边表示。[CSS]
    2. 拖拽数据存储元素列表中的元素(如果存在)。
    3. 拖拽数据存储默认反馈

从用户代理初始化拖放操作开始,直到拖放操作结束,必须禁止驱动器输入事件(例如鼠标及键盘事件)。

在拖拽操作期间,作为拖拽目标直接显示给用户的元素被称为用户的直接选择。(仅有元素可以被用户选择;其他节点禁止被用作释放目标。)另外,用户的直接选择可以不是作为拖放操作释放部分的当前选择元素的当前目标元素

用户的直接选择在用户选择不同元素时变化(使用定点设备指出或者通过其他途径选择)。当前目标元素用户的直接选择改变时改变,其变化由之后描述的文档中的事件监听器的结果决定。

当前目标元素用户的直接选择均可以为空,这意味着没有选择目标元素。它们也可以为其它(基于DOM的)文档、其他(为Web)程序中的元素。(例如,一个用户可以将文本拖拽至一个文本处理器中。)当前目标元素初始化为空。

另外,还存在一个当前拖拽操作,其值可能为“none”、“copy”、“link”及“move”。最初,其值为“none”。其值的更新按照下面步骤中描述的由用户代理进行。

在拖拽操作初始化之后、拖拽操作进行中每隔350毫秒(正负误差200毫秒),用户代理必须按照下列步骤排入一个任务

  1. 如果下一次迭代到期时用户代理仍然在处理序列中的上一次迭代,则跳过本次迭代中的这些步骤(实际上为对拖放操作“跳过错过的帧”)。
  2. 源节点触发一个拖放事件,该事件名为drag。如果该事件被撤销,用户代理必须将当前拖拽操作设为“none”(没有拖拽操作)。
  3. 如果drag事件没有被撤销,且用户没有结束拖放操作,则检查拖放操作的状态:
    1. 如果用户在上一次迭代时指定了不同的用户的直接选择(或者此次为第一次迭代),并且如果这个用户的直接选择当前目标元素,则更新当前目标元素
    2. 如果上一步造成当前目标元素改变,并且如果之前的目标元素不为空或者非DOM文档的一部分,则在之前的目标元素上触发一个拖放事件,该事件名为dragleave
    3. 否则,如果当前目标元素不是一个DOM元素,则使用平台指定的机制来确定应该执行何种拖拽操作(none、copy、link或move),并依此设置当前拖拽操作
    4. 更新拖拽反馈(例如鼠标指针)以匹配当前拖拽操作,其对应关系见下表二。
  4. 否则,如果用户结束拖放操作(例如在鼠标驱动的拖放接口中释放鼠标按键),或者如果drag事件被撤销,则其为上一次迭代。执行下列步骤,指标结束拖放操作:
    1. 源节点触发一个拖放事件,该事件名为dragend
    2. 将下列适当的步骤作为dragend事件的默认行为执行:
      • 如果释放为真,且当前目标元素为一个文本字段(例如textareatype属性为文本状态的input元素),且当前拖拽操作为“move”,且拖放操作的源为DOM中的选择
        • 用户代理应当从DOM中删除拖拽选择器所表示的范围。
      • 如果释放为真,且当前目标元素为一个文本字段(例如textareatype属性为文本状态的input元素),且当前拖拽操作为“move”,且拖放操作的源为文本字段中的选择
        • 用户代理应当从相关文本字段中删除拖拽选择。
      • 如果释放为假或者如果当前拖拽操作为“none
        • 拖拽被撤销。如果平台约定指出这将向用户展示(例如用动画展示拖拽选择回到拖放操作的源),则按照约定操作。
      • 否则
        • 事件没有默认行为。
注:我们鼓励用户代理考虑在滚动条区域拖拽的行为。例如,如果用户将一个链接拖拽至一个长页面的视窗的下部,其可能会使页面滚动以便用户可以将链接拖拽至页面的更低部分。
注:本模型独立于节点调用时所属的Document对象;事件的触发参照下面的描述,且处理模型执行的间歇参照下面的描述,不考虑在操作中涉及的文档数量。

事件摘要

本节不具规范性

下列事件属于拖放模型。

事件名称 目标 可撤销? 拖拽数据存储模式 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:”开始
  • 任意包含六个以上字符的关键词,且其由ASCII不区分大小写匹配字符串“file:”开始

dropzone内容属性的值禁止指定超过一个的反馈值(copymovelink)。如果没有指定,则相当于隐式的指定copy

如果dropzone处理步骤返回匹配,则dropzone属性匹配拖拽数据存储

如果dropzone处理步骤返回一个特定操作,则dropzone属性指定一个操作。特定的操作在这些步骤中给出。

dropzone处理步骤如下。其返回是否匹配以及是否指定操作。

  1. dropzone属性的值。
  2. 关键词集合按空格分隔的结果。
  3. 匹配为假。
  4. 操作为未指定。
  5. 对于关键词集合中的每个值(如果存在),按照其在中被发现的顺序,执行下列步骤:
    1. 关键词为该关键词。
    2. 如果关键词为“copy”、“move”或“link”,则执行下列子步骤:
      1. 如果操作仍为未指定,则设操作关键词给出的字符串。
      2. 跳转至关键词结束标记之后。
    3. 如果关键词不包含U+003A冒号字符(:),或者如果第一个这样的字符是关键词中的第一个字符或最后一个字符,则跳转至关键词结束标记之后。
    4. 种类码关键词中第一个字符到第一个U+003A冒号字符(:)之前的最后一个字符之间的子字符串,并转换为ASCII小写形式
    5. 根据种类码跳转至下列适当的步骤:
      • 如果种类码为字符串“string
        • 种类纯Unicode字符串
      • 如果种类码为字符串“file
      • 否则
        • 跳转至关键词结束标记之后。
    6. 类型关键词中第一个U+003A冒号字符(:)之后的第一个字符到最后一个字符之间的子字符串,并转换为ASCII小写形式
    7. 如果拖拽数据存储项列表中存在任意拖拽数据项种类种类中给出的种类且拖拽数据项类型为类型的项目,则设匹配为真。
    8. 关键词结束:继续下一个关键词(如果存在),或者上层算法的下一步(如果没有更多关键词)。
  6. 如果匹配为真,则算法返回匹配,否则相反。
    如果操作不是为未指定,则返回一个特定的操作。如果指定了一个特定操作,则该操作为操作中给出的一个。

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)变化(脚本)。本规范没有指定如果执行。

文本搜索API