HTML5拖放事件(Drag-and-Drop,DnD)

拖放

拖放是一种常见的特性,即抓取对象以后拖到另一个位置。在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放。

拖放是在“拖放源(drag source)”和“拖放目标(drop target)”之间传输数据的用户界面。下面例子将演示如何创建自定义拖放源和自定义拖放目标,前者传输数据而不是其文本内容,后者以某种方式相应拖放数据而不是仅显示它。

浏览器支持

Internet Explorer 9、Firefox、Opera 12、Chrome 以及 Safari 5 支持拖放。

注释:在 Safari 5.1.2 中不支持拖放。

拖放事件

  1. DataTransfer 对象:退拽对象用来传递的媒介,使用一般为Event.dataTransfer。
  2. draggable 属性:就是标签元素要设置draggable=true,否则不会有效果,例如:
    <div title="拖拽我" draggable="true">列表1</div>
  3. ondragstart 事件:当拖拽元素开始被拖拽的时候触发的事件,此事件作用在被拖曳元素上
  4. ondragenter 事件:当拖曳元素进入目标元素的时候触发的事件,此事件作用在目标元素上
  5. ondragover 事件:拖拽元素在目标元素上移动的时候触发的事件,此事件作用在目标元素上
  6. ondragleave 事件:拖拽元素在目标元素上移动的时候触发的事件,此事件作用在目标元素上
  7. ondrop 事件:被拖拽的元素在目标元素上同时鼠标放开触发的事件,此事件作用在目标元素上
  8. ondragend 事件:当拖拽完成后触发的事件,此事件作用在被拖曳元素上
  9. event.preventDefault() 方法:阻止默认的些事件方法等执行。在ondragover中一定要执行preventDefault(),否则ondrop事件不会被触发。另外,如果是从其他应用软件或是文件中拖东西进来,尤其是图片的时候,默认的动作是显示这个图片或是相关信息,并不是真的执行drop。此时需要用用document的ondragover事件把它直接干掉。
  10. event.setDataTransfer.effectAllowed 属性:就是拖拽的效果。
  11. evetn.setDataTransfer.setDragImage() 方法:指定图片或者文档元素做拖动时的视觉效果。

DnD总是基于事件且Javascript API包含两个事件集,一个是在拖放源上触发,另一个在拖放目标上触发。所有传递给DnD事件处理程序的事件对象都类似鼠标事件对象,另外他拥有dataTransfer属性。这个属性引用DataTransfer对象,该对象定义DnD API的方法和属性。

拖放源时间相当简单,我们就从他们开始。任何有HTML draggable属性的文档元素都是拖放源。当用户开始用鼠标在拖放源上拖动时,浏览器并没有选择元素内容,相反,它在这个元素上触发dragstart事件,这个事件的处理程序就调用dataTransfer.setData()指定当前可用的拖放源数据(和数据类型)。这个时间处理程序也可以设置dataTransfer.effectAllowed来指定支持“移动”、“复制”和“链接”传输操作中的集中,同时他可以调用dataTransfer.setDragImage()指定图片或者文档元素做拖动时的视觉效果。

当放置数据发生时会触发dragend事件。如果拖放源支持“移动”操作,它就会检查dataTransfer.dropEffect去看看是否实际执行了移动操作。如果执行了,数据就被传输到其他地方,你就应该从拖放源中删除它。

实例

var whenReady = (function() { // This function returns the whenReady() function
    var funcs = [];    // The functions to run when we get an event
    var ready = false; // Switches to true when the handler is triggered

    // The event handler invoked when the document becomes ready
    function handler(e) {
        // If we‘ve already run once, just return
        if (ready) return;

        // If this was a readystatechange event where the state changed to
        // something other than "complete", then we‘re not ready yet
        if (e.type === "readystatechange" && document.readyState !== "complete")
            return;

        // Run all registered functions.
        // Note that we look up funcs.length each time, in case calling
        // one of these functions causes more functions to be registered.
        for(var i = 0; i < funcs.length; i++)
            funcs[i].call(document);

        // Now set the ready flag to true and forget the functions
        ready = true;
        funcs = null;
    }

    // Register the handler for any event we might receive
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", handler, false);
        document.addEventListener("readystatechange", handler, false);
        window.addEventListener("load", handler, false);
    }
    else if (document.attachEvent) {
        document.attachEvent("onreadystatechange", handler);
        window.attachEvent("onload", handler);
    }

    // Return the whenReady function
    return function whenReady(f) {
        if (ready) f.call(document); // If already ready, just run it
        else funcs.push(f);          // Otherwise, queue it for later.
    }
}());

whenReady(function() {
    var clock = document.getElementById("clock");  // The clock element
    var icon = new Image();                        // An image to drag
    icon.src = "clock-icon.png";                   // Image URL

    // Display the time once every minute
    function displayTime() {
        var now = new Date();               // Get current time
        var hrs = now.getHours(), mins = now.getMinutes();
        if (mins < 10) mins = "0" + mins;
        clock.innerHTML = hrs + ":" + mins; // Display current time
        setTimeout(displayTime, 60000);     // Run again in 1 minute
    }
    displayTime();

    // Make the clock draggable
    // We can also do this with an HTML attribute: <span draggable="true">...
    clock.draggable = true;

    // Set up drag event handlers
    clock.ondragstart = function(event) {
        var event = event || window.event; // For IE compatability

        // The dataTransfer property is key to the drag-and-drop API
        var dt = event.dataTransfer;

        // Tell the browser what is being dragged.
        // The Date() constructor used as a function returns a timestamp string
        dt.setData("Text", Date() + "\n");

        // Tell the browser to drag our icon to represent the timestamp, in
        // browsers that support that. Without this line, the browser may
        // use an image of the clock text as the value to drag.
        if (dt.setDragImage) dt.setDragImage(icon, 0, 0);
    };
});
</script>
<style>
#clock { /* Make the clock look nice */
    font: bold 24pt sans; background: #ddf; padding: 10px;
    border: solid black 2px; border-radius: 10px;
}
</style>
<h1>Drag timestamps from the clock</h1>
<span id="clock"></span>  <!-- The time is displayed here -->
<textarea cols=60 rows=20></textarea> <!-- You can drop timestamps here -->

拖放目标比拖放源更棘手。任何元素都可以是拖放目标,这不需要像拖放源一样设置HTML属性,只需要简单地定义合适的时间监听程序。有4个事件在拖放目标上触发。当拖放对象进入文档元素时,浏览器在这个元素上触发dragenter事件。拖放目标应该使用dataTransfer.types属性确定拖放对象的可用数据是否是它能理解的格式。如果检查成功,拖放目标必须让用户和浏览器都知道它对防止感兴趣。可以通过改变他的边框或者背景颜色来向用户反馈。令人吃惊的是,拖放目标通过取消事件来告知浏览器它对防止感兴趣。如果元素不取消浏览器发送给它的draggenter事件,浏览器将不会把它作为这次拖放的拖放目标,并不会向它在发送任何事件。但如果拖放目标取消了dragenter事件,浏览器将发送dragover事件表示用户继续在目标元素上拖动对象。再一次令人吃惊的是,拖放目标必须监听且取消所有这些事情来表明它对放置感兴趣。如果拖放目标向指定它只允许移动、复制和链接操作,它应该使用dragover事件处理程序来设置dataTransfer.dropEffect

如果用户移动拖放对象离开通过取消事件表明有兴趣的拖放目标,那么在拖放目标上将触发dragleave事件。这个事件的处理程序应该恢复元素的边框或者背景颜色或者取消任何其他为相应dragenter事件而执行的可视化反馈。遗憾的是,dragenter和draleave事件会冒泡,如果拖放目标内部嵌套元素,想知道dragleave事件表示拖放对象从拖放目标离开到目标外的事件还是到目标内的事件非常困难。

最后,如果用户把拖放队形放置在拖放目标上,拖放目标上会触发drop事件。这个事件的处理程序应该使用dataTransfer.getData()获取传输的数据并做一些适当的处理。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>test</title>
    <style type="text/css">
        *{padding: 0px;margin:0px;}
        .droppable{
            background: yellow;
        }
        .dnd{margin:20px;border:2px solid blue;padding: 20px;}
    </style>
    <script type="text/javascript">
        window.onload = function(){
            var lists = document.getElementsByTagName(‘ul‘);
            var regexp = /\bdnd\b/;
            for (var i=0;i<lists.length;i++)
                if (regexp.test(lists[i].className)) dnd(lists[i]);
            function dnd(list){
                var original_class = list.className;
                var entered = 0;
                list.ondragenter = function(e){
                    e = e || window.event;
                    var from = e.relatedTarget;
                    entered++;
                    if ((from &&!isChild(from,list)) || entered ==1) {
                        var dt = e.dataTransfer;
                        var types = dt.types;
                        if (!types ||(types.contains&&types.contains("text/plain"))||(types.indexOf &&types.indexOf("text/plain")!=-1)) {
                            list.className = original_class + " droppable";
                            return false;
                        }
                        return;
                    }
                    return false;
                };
                list.ondragover = function(e){return false;}

                list.ondragleave = function(e){
                    e = e || window.event;
                    var to = e.relatedTarget;
                    entered--;
                    if (to && !isChild(to,list) || entered <= 0) {
                        list.className = original_class;
                        entered = 0;
                    }
                    return false;
                };

                list.ondrop = function(e){
                    e = e || window.event;
                    var dt = e.dataTransfer;
                    var text = dt.getData("Text");
                    if (text) {
                        var item = document.createElement("li");
                        item.draggable = true;
                        item.appendChild(document.createTextNode(text));
                        list.appendChild(item);
                        list.className = original_class;
                        entered = 0;
                        return false;
                    }
                };

                var items = list.getElementsByTagName("li");
                for (var i=0;i<items.length;i++)
                    items[i].draggable = true;
                list.ondragstart = function(e){
                    var e = e || window.event;
                    var target = e.target || e.srcElemnt;
                    if (target.tagName !=="LI") return false;
                    var dt = e.dataTransfer;
                    dt.setData("Text", target.innerText || target.textContent);
                    dt.effectAllowed = "move";
                };

                list.ondragend = function(e){
                    e = e || window.event;
                    var target = e.target || e.srcElemnt;
                    if (e.dataTransfer.dropEffect ==="move") target.parentNode.removeChild(target);
                }

                function isChild(a,b){
                    for(; a; a = a.parentNode) if (a === b) return true;
                    return false;
                }
            }
        }
    </script>
</head>
<body>
    <ul class="dnd">
        <li>测试测试测试测试-1</li>
        <li>测试测试测试测试-2</li>
        <li>测试测试测试测试-3</li>
        <li>测试测试测试测试-4</li>
    </ul>
    <ul class="dnd">
        <li>测试测试测试测试-5</li>
        <li>测试测试测试测试-6</li>
        <li>测试测试测试测试-7</li>
        <li>测试测试测试测试-8</li>
    </ul>
    <ul class="dnd">
        <li>测试测试测试测试-9</li>
        <li>测试测试测试测试-10</li>
        <li>测试测试测试测试-11</li>
        <li>测试测试测试测试-12</li>
    </ul>
</body>
</html>
时间: 2024-10-19 01:49:10

HTML5拖放事件(Drag-and-Drop,DnD)的相关文章

原生拖拽,拖放事件(drag and drop)

原生拖拽,拖放事件(drag and drop) 拖拽,拖放事件可以通过拖拽实现数据传递,达到良好的交互效果,如:从操作系统拖拽文件实现文件选择,拖拽实现元素布局的修改. drag and drop事件流程 一个完整的drag and drop流程通常包含以下几个步骤: 设置可拖拽目标.设置属性draggable="true"实现元素的可拖拽. 监听dragstart设置拖拽数据 为拖拽操作设置反馈图标(可选) 设置允许的拖放效果,如copy,move,link 设置拖放目标,默认情况

HTML5 拖放(Drag 和 Drop)功能开发——基础实战

随着HTML5的普及度越来越高,现在写代码也遇到一些了,经过同事的点播开展了一次Dojo活动用以技术交流,我也乘此机会将HTML5的拖放功能整理了一下. 简介 拖拽(Drag/Drop)是个非常普遍的功能.在生活中,拖放物品其实是相当常见的一个动作.标榜“互联网生活尖凿狮”的程序猿也在一直试图用鼠标模拟出“手”的操作,用来给用户以更好的体验,你可以抓住一个对象,并且拖动到你想放置的区域.很多javascript都类似实现了相关的功能,例如,jQueryUI的draganddrop组件,比如<JS

HTML5 拖放(Drag 和 Drop)详解与实例

简介 拖放是一种常见的特性,即抓取对象以后拖到另一个位置. 在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放. 先点击一个小例子:在用户开始拖动 <p> 元素时执行 JavaScript <p draggable="true" ondragstart="myFunction(event)">拖动我!</p> 提示: 链接和图片默认是可拖动的,不需要 draggable 属性. 定义和用法 在拖放的过程中会触发以下事件:

HTML5 拖放(Drag 和 Drop)功能开发——浅谈dataTransfer对象

[前言] 之前我已经为大家介绍过一篇有关HTML5中原生拖拽的相关知识了.今天为大家介绍HTML5拖拽中的其他一些关于dataTransfer对象的知识和应用. dataTransfer对象 之前的一篇文章中也有提及到dataTransfer对象,那会只是想通过dataTransfer对象来将被拖拽元素的id进行传递,使得目标元素可以通过相应的dataTransfer对象来获取id进行对应操作. 成员表 属性 描述 dropEffect 设置或获取拖曳操作的类型和要显示的光标类型. effect

HTML5 拖放(Drag 和 Drop)

一.定义 拖放是一种常见的特性,即抓取对象以后拖到另一个位置.在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放. Internet Explorer 9+, Firefox, Opera, Chrome, 和 Safari 支持拖动.Safari 5.1.2不支持拖动 二.使用 设置元素为可拖放:为了使元素可拖动,把 draggable 属性设置为 true 拖动什么 :ondragstart 和 setData( ),其中ondragstart 它规定了被拖动的数据.setData(

HTML5 CSS3 专题 : 拖放 (Drag and Drop)

本来准备写一个支持多图片拖拽上传的例子,但是为了更好的理解,先介绍一下HTML5的拖放. 拖放(Drag 和 drop)是 HTML5 标准的组成部分. 浏览器支持 Internet Explorer 9.Firefox.Opera 12.Chrome 以及 Safari 5 支持拖放. 被拖元素,dragElement : 1.添加事件:ondragstart 2.添加属性:dragable 放置元素,dropElement: 1.添加事件:ondargenter , ondragover ,

Android 用户界面---拖放(Drag and Drop)(三)

设计拖放操作 本节主要内容如下: 1.  如何开始拖拽: 2.  在拖拽期间如何响应事件: 3.  如何响应落下事件: 4.  如何结束拖放操作. 开始拖拽 用户使用一个拖拽手势开始拖拽,通常是在View对象上长按.在响应中,应该做下列事情: 1.  必要时,给要移动的数据创建一个ClipData和ClipData.Item对象,作为ClipData对象的一部分,在ClipData对象内部的ClipDescription对象中保存了元数据.因为拖放操作不代表数据的移动,因此可以使用null来代替

HTML5拖放事件-上传图片预览功能(学习笔记)

主要用到的知识点有dataTransfer对象和FileReader(读取文件信息) 1.创建简单的HTML标签: <body> <div id="box">请将图片拖拽至此</div> <ul></ul> </body> 2.给标签加上简单的样式: <style type="text/css"> div{ width: 300px; height: 300px; margin:10

Android 用户界面---拖放(Drag and Drop)(二)

拖拽事件监听器和回调方法 View对象既可以用实现View.OnDragListener接口的拖放事件监听器,也可以用View对象的onDragEvent(DragEvent)回调方法来接收拖拽事件.当系统调用这个回调方法或监听器时,都要给它们传递一个DragEvent对象. 在大多数场景中你可能会使用监听器.因为在设计UI界面时,通常没有View类的子类,而使用回调方法,为了覆写这个方法,就会强制你使用View类及子类.相比之下,你可以实现一个监听器类,然后再几个不同的View对象中使用.你还