拖拉事件

拖拉指的是,用户在某个对象上按下鼠标键不放,拖动它到另一个位置,然后释放鼠标键,将该对象放在那里。

拖拉的对象有好几种,包括Element节点、图片、链接、选中的文字等等。在HTML网页中,除了Element节点默认不可以拖拉,其他(图片、链接、选中的文字)都是可以直接拖拉的。为了让Element节点可拖拉,可以将该节点的draggable属性设为true。

<div draggable="true">
此区域可拖拉
</div>

draggable属性可用于任何Element节点,但是图片(img元素)和链接(a元素)不加这个属性,就可以拖拉。对于它们,用到这个属性的时候,往往是将其设为false,防止拖拉。

注意,一旦某个Element节点的draggable属性设为true,就无法再用鼠标选中该节点内部的文字或子节点了。

事件种类

当Element节点或选中的文本被拖拉时,就会持续触发拖拉事件,包括以下一些事件。

  • drag事件:拖拉过程中,在被拖拉的节点上持续触发。

  • dragstart事件:拖拉开始时在被拖拉的节点上触发,该事件的target属性是被拖拉的节点。通常应该在这个事件的监听函数中,指定拖拉的数据。

  • dragend事件:拖拉结束时(释放鼠标键或按下escape键)在被拖拉的节点上触发,该事件的target属性是被拖拉的节点。它与dragStart事件,在同一个节点上触发。不管拖拉是否跨窗口,或者中途被取消,dragend事件总是会触发的。

  • dragenter事件:拖拉进入当前节点时,在当前节点上触发,该事件的target属性是当前节点。通常应该在这个事件的监听函数中,指定是否允许在当前节点放下(drop)拖拉的数据。如果当前节点没有该事件的监听函数,或者监听函数不执行任何操作,就意味着不允许在当前节点放下数据。在视觉上显示拖拉进入当前节点,也是在这个事件的监听函数中设置。

  • dragover事件:拖拉到当前节点上方时,在当前节点上持续触发,该事件的target属性是当前节点。该事件与dragenter事件基本类似,默认会重置当前的拖拉事件的效果(DataTransfer对象的dropEffect属性)为none,即不允许放下被拖拉的节点,所以如果允许在当前节点drop数据,通常会使用preventDefault方法,取消重置拖拉效果为none。

  • dragleave事件:拖拉离开当前节点范围时,在当前节点上触发,该事件的target属性是当前节点。在视觉上显示拖拉离开当前节点,就在这个事件的监听函数中设置。

  • drop事件:被拖拉的节点或选中的文本,释放到目标节点时,在目标节点上触发。注意,如果当前节点不允许drop,即使在该节点上方松开鼠标键,也不会触发该事件。如果用户按下Escape键,取消这个操作,也不会触发该事件。该事件的监听函数负责取出拖拉数据,并进行相关处理。

  • 拖拉过程只触发以上这些拖拉事件,尽管鼠标在移动,但是鼠标事件不会触发。

  • 将文件从操作系统拖拉进浏览器,不会触发dragStart和dragend事件。

  • dragenter和dragover事件的监听函数,用来指定可以放下(drop)拖拉的数据。由于网页的大部分区域不适合作为drop的目标节点,所以这两个事件的默认设置为当前节点不允许drop。如果想要在目标节点上drop拖拉的数据,首先必须阻止这两个事件的默认行为,或者取消这两个事件。

<div ondragover="return false">
<div ondragover="event.preventDefault()">

  

上面代码中,如果不取消拖拉事件或者阻止默认行为,就不可能在div节点上drop被拖拉的节点。

拖拉事件用一个DragEvent对象表示,该对象继承MouseEvent对象,因此也就继承了UIEvent和Event对象。DragEvent对象只有一个独有的属性DataTransfer,其他都是继承的属性。DataTransfer属性用来读写拖拉事件中传输的数据,详见下文《DataTransfer对象》的部分。

下面的例子展示,如何动态改变被拖动节点的背景色。

div.addEventListener("dragstart", function(e) {
this.style.backgroundColor = "red";
}, false);
div.addEventListener("dragend", function(e) {
this.style.backgroundColor = "green";
}, false);

  

上面代码中,div节点被拖动时,背景色会变为红色,拖动结束,又变回绿色。

下面是一个例子,显示如何实现将一个节点从当前父节点,拖拉到另一个父节点中。

/ HTML代码为
// <div class="dropzone">
// <div id="draggable" draggable="true">
// 该节点可拖拉
// </div>
// </div>
// <div class="dropzone"></div>
// <div class="dropzone"></div>
// <div class="dropzone"></div> // 被拖拉节点
var dragged; document.addEventListener("dragstart", function( event ) {
// 保存被拖拉节点
dragged = event.target;
// 被拖拉节点的背景色变透明
event.target.style.opacity = .5;
}, false); document.addEventListener("dragend", function( event ) {
// 被拖拉节点的背景色恢复正常
event.target.style.opacity = "";
}, false); document.addEventListener("dragover", function( event ) {
// 防止拖拉效果被重置,允许被拖拉的节点放入目标节点
event.preventDefault();
}, false); document.addEventListener("dragenter", function( event ) {
// 目标节点的背景色变紫色
// 由于该事件会冒泡,所以要过滤节点
if ( event.target.className == "dropzone" ) {
event.target.style.background = "purple";
}
}, false); document.addEventListener("dragleave", function( event ) {
// 目标节点的背景色恢复原样
if ( event.target.className == "dropzone" ) {
event.target.style.background = "";
}
}, false); document.addEventListener("drop", function( event ) {
// 防止事件默认行为(比如某些Elment节点上可以打开链接)
event.preventDefault();
if ( event.target.className == "dropzone" ) {
// 恢复目标节点背景色
event.target.style.background = "";
// 将被拖拉节点插入目标节点
dragged.parentNode.removeChild( dragged );
event.target.appendChild( dragged );
}
}, false);

  

DataTransfer对象概述

所有的拖拉事件都有一个dataTransfer属性,用来保存需要传递的数据。这个属性的值是一个DataTransfer对象。

拖拉的数据保存两方面的数据:数据的种类(又称格式)和数据的值。数据的种类是一个MIME字符串,比如 text/plain或者image/jpeg,数据的值是一个字符串。一般来说,如果拖拉一段文本,则数据默认就是那段文本;如果拖拉一个链接,则数据默认就是链接的URL。

当拖拉事件开始的时候,可以提供数据类型和数据值;在拖拉过程中,通过dragenter和dragover事件的监听函数,检查数据类型,以确定是否允许放下(drop)被拖拉的对象。比如,在只允许放下链接的区域,检查拖拉的数据类型是否为text/uri-list。

发生drop事件时,监听函数取出拖拉的数据,对其进行处理。

DataTransfer对象的方法

DataTransfer对象有以下方法。

(1)setData()

setData方法用来设置事件所带有的指定类型的数据。它接受两个参数,第一个是数据类型,第二个是具体数据。如果指定的类型在现有数据中不存在,则该类型将写入types属性;如果已经存在,在该类型的现有数据将被替换。

event.dataTransfer.setData("text/plain", "Text to drag");

  

上面代码为事件加入纯文本格式的数据。

如果拖拉文本框或者拖拉选中的文本,会默认将文本数据添加到dataTransfer属性,不用手动指定。

<div draggable="true" ondragstart="
event.dataTransfer.setData('text/plain', 'bbb')">
aaa
</div>

  

上面代码中,拖拉数据实际上是bbb,而不是aaa。

下面是添加其他类型的数据。由于text/plain是最普遍支持的格式,为了保证兼容性,建议最后总是将数据保存一份纯文本的格式。

var dt = event.dataTransfer;

// 添加链接
dt.setData("text/uri-list", "http://www.example.com");
dt.setData("text/plain", "http://www.example.com");
// 添加HTML代码
dt.setData("text/html", "Hello there, <strong>stranger</strong>");
dt.setData("text/plain", "Hello there, <strong>stranger</strong>");
// 添加图像的URL
dt.setData("text/uri-list", imageurl);
dt.setData("text/plain", imageurl);

  可以一次提供多种格式的数据。

var dt = event.dataTransfer;
dt.setData("application/x-bookmark", bookmarkString);
dt.setData("text/uri-list", "http://www.example.com");
dt.setData("text/plain", "http://www.example.com");

  上面代码中,通过在同一个事件上面,存放三种类型的数据,使得拖拉事件可以在不同的对象上面,drop不同的值。注意,第一种格式是一个自定义格式,浏览器默认无法读取,这意味着,只有某个部署了特定代码的节点,才可能drop(读取到)这个数据。

getData()

getData方法接受一个字符串(表示数据类型)作为参数,返回事件所带的指定类型的数据(通常是用setData方法添加的数据)。如果指定类型的数据不存在,则返回空字符串。通常只有drop事件触发后,才能取出数据。如果取出另一个域名存放的数据,将会报错。

下面是一个drop事件的监听函数,用来取出指定类型的数据。

function onDrop(event){
var data = event.dataTransfer.getData("text/plain");
event.target.textContent = data;
event.preventDefault();
}

  

上面代码取出拖拉事件的文本数据,将其替换成当前节点的文本内容。注意,这时还必须取消浏览器的默认行为,因为假如用户拖拉的是一个链接,浏览器默认会在当前窗口打开这个链接。

getData方法返回的是一个字符串,如果其中包含多项数据,就必须手动解析。

function doDrop(event){
var lines = event.dataTransfer.getData("text/uri-list").split("\n");
for (let line of lines) {
let link = document.createElement("a");
link.href = line;
link.textContent = line;
event.target.appendChild(link);
}
event.preventDefault();
}

  

上面代码中,getData方法返回的是一组链接,就必须自行解析。

类型值指定为URL,可以取出第一个有效链接。

var link = event.dataTransfer.getData("URL");

  

clearData()

clearData方法接受一个字符串(表示数据类型)作为参数,删除事件所带的指定类型的数据。如果没有指定类型,则删除所有数据。如果指定类型不存在,则原数据不受影响。

event.dataTransfer.clearData("text/uri-list");

  上面代码清除事件所带的URL数据。

setDragImage()

拖动过程中(dragstart事件触发后),浏览器会显示一张图片跟随鼠标一起移动,表示被拖动的节点。这张图片是自动创造的,通常显示为被拖动节点的外观,不需要自己动手设置。setDragImage方法可以用来自定义这张图片,它接受三个参数,第一个是img图片元素或者canvas元素,如果省略或为null则使用被拖动的节点的外观,第二个和第三个参数为鼠标相对于该图片左上角的横坐标和右坐标。

下面是一个例子。

// HTML代码为
// <div id="drag-with-image" class="dragdemo" draggable="true">
drag me
// </div> var div = document.getElementById("drag-with-image");
div.addEventListener("dragstart", function(e) {
var img = document.createElement("img");
img.src = "http://path/to/img";
e.dataTransfer.setDragImage(img, 0, 0);
}, false);

  

javascript高级程序设计---拖拉事件的更多相关文章

  1. 《JAVASCRIPT高级程序设计》事件委托和模拟事件

    由于事件处理程序可以为现代web应用提供交互能力,因此许多开发人员不分青红皂白向页面中添加大量的处理程序:这在某些语言中不会导致问题,但是在javascript,事件处理程序数量直接关系到页面的整体运 ...

  2. 《JAVASCRIPT高级程序设计》事件处理程序和事件类型

    一.事件流 谈到事件,首要要理解事件流的概念:事件流是指从页面接受事件的顺序:“DOM2级事件”规定事件流包括三个阶段:事件捕获阶段.处于目标阶段和事件冒泡阶段.目前大部分的浏览器的事件流是事件冒泡, ...

  3. JavaScript高级程序设计笔记 事件冒泡和事件捕获

    1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body> <div> click me! </div> & ...

  4. javascript高级程序设计---js事件思维导图

    绘制思维软件与平时用的笔记,以及导出功能,这三个问题综合起来,于是我把思维导图分开画 1.js事件的基本概念 2.js事件的事件处理程序 3.js事件的事件对象

  5. 《javascript高级程序设计》 touch事件的一个小错误

    最近一段时候都在拜读尼古拉斯大神的<javascript高级程序设计>,真的是一本好书,通俗易懂,条理比<javascript权威指南>好理解一些,当然<javascri ...

  6. 读书笔记(05) - 事件 - JavaScript高级程序设计

    HTML依托于JavaScript来实现用户与WEB网页之间的动态交互,接收用户操作并做出相应的反馈,而事件在此间则充当桥梁的重要角色. 日常开发中,经常会为某个元素绑定一个事件,编写相应的业务逻辑, ...

  7. 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介

    前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...

  8. 【javascript学习——《javascript高级程序设计》笔记】DOM操作

    DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口).DOM描绘了一个层次节点树,允许开发人员添加.移除和修改. 1.节点层次 <html> <head& ...

  9. 《JavaScript高级程序设计》读书笔记--前言

    起因 web编程过程使用javascript时感觉很吃力,效率很低.根本原因在于对javascript整个知识体系不熟,看来需要找些书脑补一下,同时欢迎众网友监督. 大神推荐书籍 看了博客大神们推荐的 ...

随机推荐

  1. hdu 2014 青年歌手大奖赛_评委会打分

    题意: 输入N个数,去掉最大和最小的数,求剩余的数的平均数. 解法: 找到分别最大和最小的数,然后从总和中减去他们,再求平均数(不要排序): 1: #include<stdlib.h> 2 ...

  2. 常见linux命令释义(第三天)

    今天晚上看鸟哥的私房菜,边学边写笔记. 在linux中压缩大多是.tar, .tar.gz , .tgz, /gz, .bz2等. .gz 是通过gzip压缩的文件. .bz2 是通过bzip2压缩的 ...

  3. Ajax 简述

    说到Ajax大家一定不陌生,但是真要具体说说它是什么?估计给出完整定义的人应该不多. W3C上给Ajax的具体定义为: AJAX = Asynchronous JavaScript and XML(异 ...

  4. POJ1050To the Max(求最大子矩阵)

    题目链接 题意:给出N*N的矩阵,求一个子矩阵使得子矩阵中元素和最大 分析: 必备知识:求一组数的最大连续和 int a[N]; ,maxn = -INF; ; i <= n; i++) { i ...

  5. CSS3的transition动画功能

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. RBAC权限设计实例

    http://blog.csdn.net/painsonline/article/details/7183629 实现业务系统中的用户权限管理 B/S系统中的权限比C/S中的更显的重要,C/S系统因为 ...

  7. uC/OS-II类型定义

    /*************************************************************************************************** ...

  8. sudo 出现unable to resolve host 解决方法

    inux 环境, 假设这台机器名字叫dev(机器的hostname), 每次执行sudo 就出现这个警告讯息:sudo: unable to resolve host dev虽然sudo 还是可以正常 ...

  9. 20145212 实验三《敏捷开发与XP实践》

    20145212 实验三<敏捷开发与XP实践> 实验内容 使用git上传代码 与20145223同学一组,使用git相互更改代码 同组实验报告链接:http://www.cnblogs.c ...

  10. 【C++11】新特性——auto的使用

    [C++11]新特性——auto的使用 C++11中引入的auto主要有两种用途:自动类型推断和返回值占位.auto在C++98中的标识临时变量的语义,由于使用极少且多余,在C++11中已被删除.前后 ...