HTML5魔法堂:全面理解Drag & Drop API

一、前言                                   

  在HTML4的时代,各前端工程师为了实现拖拽功能可说是煞费苦心,初听HTML5的DnD API觉得那些痛苦的日子将一去不复返,但事实又是怎样的呢?下面我们一起来看看DnD API的真面目吧!

 

二、由于篇幅较长,特设目录一陀                      

三、HTML4下实现简单拖拽

四、HTML5下实现简单拖拽

五、如何启用DnD效果

六、draggable属性详解

七、DnD的生命周期

八、DnD中最重要的数据传递对象──DataTransfer对象

九、[object DataTransferItemList]类型

十、[object DataTransferItem]类型

十一、浏览器支持

十二、特征检测是否支持HTML5的DnD API

十三、总结

十四、参考

十五、勘误

十六、书评

 

三、HTML4下实现简单拖拽                          

功能:实现在div#title上按下鼠标左键并移动鼠标时,拖拽整个div#dialog,但释放鼠标时停止拖拽。

html代码片断

<div id="dialog">
     <div id="title">
        Hi there!
     </div>
     <div id="content">
        Welcome here every one. We would learn the HTML5 feature DnD API now!
     <div>
</div>

js代码片断

DnD && DnD(document.getElementById('title'), document.getElementById('dialog'));

DnD.js工具库

;(function(exports, contains){
    var evtPrefix = '',
        off = 'removeEventListener',
        on = 'addEventListener' in document  && 'addEventListener' ||
            (evtPrefix = 'on', off = 'detachEvent') && 'attachEvent';
    var docEl = document.documentElement,
        body = document.body;

    var css = function(el, prop, expectedVal){
            var val;
            if (el.currentStyle){
                 val = el.currentStyle[prop];
            }
            else{
                val = window.getComputedStyle(el, null)[prop];
            }
            if (arguments.length === 3){
                if (typeof expectedVal === 'string')
                    return val === expectedVal;
                if (Object.prototype.toString.call(expectedVal) === '[object RegExp]')
                    return expectedVal.test(val);
                return false;
            }
            return val;
        };

    // 修正获取元素离页面左上角距离的bug
    var props = [['marginLeft', 'marginTop'], ['borderLeft', 'borderTop'], ['left', 'top']];
    var getOffsetXY = function(el){
            var oxy = {ox: el.offsetLeft, oy: el.offsetTop};
            if (el.offsetParent){
                var poxy = getOffsetXY(el.offsetParent);
                oxy = {ox: oxy.ox + poxy.ox, oy: oxy.oy + poxy.oy};
            }
            else if (css(el, 'position', /relative|absolute/i)){
                for (var i = 0, prop; prop = props[i++];){
                    oxy = {
                        ox: oxy.ox + (parseInt(css(el, prop[0])) || 0),
                        oy: oxy.oy + (parseInt(css(el, prop[1])) || 0)
                    };
                }
            }
            return oxy;
        };
    var getPointXY = function(evt){
            if ('pageX' in evt){
                return {
                        x: evt.pageX,
                        y: evt.pageY
                    };
            }
            else{
                return {
                        x: evt.clientX + (docEl && docEl.scrollLeft || body && body.scrollLeft || 0) - (docEl && docEl.clientLeft || body && body.clientLeft || 0),
                        y: evt.clientY + (docEl && docEl.scrollLeft || body && body.scrollTop || 0) - (docEl && docEl.clientLeft || body && body.clientTop || 0)
                    };
            }
        };

    exports.DnD = function(dragEl, addedEl){
        if (!this instanceof DnD){
            return new DnD(dragEl, addedEl);
        }

        var dragEls = [];
        if (contains(dragEl, addedEl)){
            dragEls.push({
                el: dragEl,
                ox: 0,
                oy: 0
            });
        }
        else if (contains(addedEl, dragEl)){
            dragEls.push({
                el: addedEl,
                ox: 0,
                oy: 0
            });
        }
        else{
            dragEls = [{
                el: addedEl,
                ox: 0,
                oy: 0
            },{
                el: dragEl,
                ox: 0,
                oy: 0
            }];
        }
        var ox, oy;
        dragEl[on](evtPrefix + 'mousedown', function(evt){
            evt = evt || window.event;

            var pointXY = getPointXY(evt);
            ox = pointXY.x;
            oy = pointXY.y;

            for (var i = 0, currEl; currEl = dragEls[i++];){
                var oxy = getOffsetXY(currEl.el);
                currEl.ox = oxy.ox;
                currEl.oy = oxy.oy;
                currEl.el.style.position = 'absolute';
                currEl.el.style.left = currEl.ox + 'px';
                currEl.el.style.top = currEl.oy + 'px';
            }

            var onDOCMousemove = function(evt){
                evt = evt || window.event;
                var dx = evt.clientX - ox;
                var dy = evt.clientY - oy;
                for (var i = 0, currEl; currEl = dragEls[i++];){
                    currEl.el.style.left = (currEl.ox + dx) + 'px';
                    currEl.el.style.top = (currEl.oy + dy) + 'px';
                }
            };
            document[on](evtPrefix + 'mousemove', onDOCMousemove);
            document[on](evtPrefix + 'mouseup', function(evt){
                evt = evt || window.event;
                document[off](evtPrefix + 'mousemove', onDOCMousemove);
            });
        });
    };
}(window, window.contains));

contains.js工具库

;(function(exports){
    exports.contains = function(pel, cel){
        // ie
        if (pel.contains){
            return pel.contains(cel);
        }
        else if(pel.compareDocumentPosition){
            return !!pel.compareDocumentPosition(cel) & 16;
        }
        else{
            var p;
            while ((p = cel.parentNode) && p.nodeType === 1){
                if (pel === p) return true;
            }
            return true;
        }
    };
}(window));

具体代码地址:https://github.com/fsjohnhuang/DnD-polyfill/blob/master/sample/sample3/

 

四、HTML5实现简单拖拽                          

功能:实现在div#title上按下鼠标左键并移动鼠标时,拖拽整个div#dialog,但释放鼠标时停止拖拽。下面的例子仅能在FF下运行

html代码片段

<div id="dialog">
     <div id="title" draggable="true">
        Hi there!
     </div>
     <div id="content">
        Welcome here every one. We would learn the HTML5 feature DnD API now!
     <div>
</div>

js代码片段

DnD && DnD(document.getElementById('title'), document.getElementById('dialog'));

DnD.js工具库

;(function(exports, contains){
    var css = function(el, prop, expectedVal){
            var val = window.getComputedStyle(el, null)[prop];
            if (arguments.length === 3){
                if (typeof expectedVal === 'string')
                    return val === expectedVal;
                if (Object.prototype.toString.call(expectedVal) === '[object RegExp]')
                    return expectedVal.test(val);
                return false;
            }
            return val;
        };
    var props = [['marginLeft', 'marginTop'], ['borderLeft', 'borderTop'], ['left', 'top']];
    var getOffsetXY = function(el){
            var oxy = {ox: el.offsetLeft, oy: el.offsetTop};
            if (el.offsetParent){
                var poxy = getOffsetXY(el.offsetParent);
                oxy = {ox: oxy.ox + poxy.ox, oy: oxy.oy + poxy.oy};
            }
            else if (css(el, 'position', /relative|absolute/i)){
                for (var i = 0, prop; prop = props[i++];){
                    oxy = {
                        ox: oxy.ox + (parseInt(css(el, prop[0])) || 0),
                        oy: oxy.oy + (parseInt(css(el, prop[1])) || 0)
                    };
                }
            }
            return oxy;
        };
    var setXY = function(e, dragEls, ox, oy){
            var dx = e.clientX - ox;
            var dy = e.clientY - oy;
            dragEls.forEach(function(item, index, dragEls){
                item.el.style.left = (item.ox + dx) + 'px';
                item.el.style.top = (item.oy + dy) + 'px';
            });
    };

    exports.DnD = function(dragEl, addedEl){
        if (!this instanceof DnD){
            return new DnD(dragEl, addedEl);
        }

        var dragEls = [], addElements = [];
        if (contains(dragEl, addedEl)){
            dragEls.push({
                el: dragEl,
                ox: 0,
                oy: 0
            });
        }
        else if (contains(addedEl, dragEl)){
            dragEls.push({
                el: addedEl,
                ox: 0,
                oy: 0
            });
        }
        else{
            dragEls = [{
                el: addedEl,
                ox: 0,
                oy: 0
            },{
                el: dragEl,
                ox: 0,
                oy: 0
            }];
        }
        var ox,oy;
        dragEl.addEventListener('dragstart', function(e){
            e.dataTransfer.setData('Text', '');
            e.dataTransfer.setDragImage(document.createElement('div'), 0, 0);
            e.dataTransfer.effectAllowed = 'move';
            if (ox == null){
                    ox = e.pageX;
                    oy = e.pageY;
                    dragEls.forEach(function(item,index,dragEls){
                        var oxy = getOffsetXY(item.el);
                        item.ox = oxy.ox;
                        item.oy = oxy.oy;
                        item.el.style.position = 'absolute';
                        item.el.style.left = item.ox + 'px';
                        item.el.style.top = item.oy + 'px';
                    });
                    // 由于dragover是在拖动一段距离后才会触发,从而导致被拖动的元素出现突然开始移动的效果
                    // 通过在dragstart中修改被拖动元素offsetTop/Left可优化该情况
                    setXY(e, dragEls, ox, oy);
            }
        }, false);
        document.addEventListener('dragover', function(e){
            e.preventDefault();
            e.dataTransfer.dropEffect = 'move';
            setXY(e, dragEls, ox, oy);
        }, false);
        document.addEventListener('drop', function(e){
            e.preventDefault();
            e.stopPropagation();
        }, false);
    };
}(window, window.contains));

contains.js工具库与上一节的相同

具体代码地址:https://github.com/fsjohnhuang/DnD-polyfill/blob/master/sample/sample4/

 

五、如何启用DnD效果                            

html片段

<div id="drag" draggable="true" style="width:100px;height:50px;background-color:red;">
test
</div>

js片段

var drag = document.getElementById('drag');
drag.onselectstart = function(){return false;};
// FF下拖拽时,默认不会生成一个被拖拽元素的阴影并跟随鼠标移动
// 需通过e.dataTransfer.setData来启动该效果
drag.ondragstart = function(e){
    e.dataTransfer.setData('text', e.target.innerHTML);
};

关键点:

1. 为触发拖拽的元素添加 draggable="true" 特性,用于启动HTML5的DnD功能(即元素的 dragstart 事件可被触发);

2. 在FF下即使添加 draggable="true" 特性,但仅仅会触发 dragstart 事件,但DnD功能并没有被完全打开(拖拽元素时没有任何视觉效果),需要调用 event.dataTransfer.setData('Text','') 彻底开启DnD功能。

3. 在Safari4下则需要借助CSS规则来启动DnD功能, [draggable=true]{ -webkit-user-drag: element; } 

 

六、draggable属性详解                              

作用:用于指定标签是否可被拖拽

属性值范围如下:

1.  true ,表示可被拖拽

2.  false ,表示不可被拖拽

3.  auto ,默认值,img和带href属性的a标签则表示可拖拽,其他标签表示不可被拖拽

4. 其他值,表示不可被拖拽

 

七、DnD生命周期                                  

1. 被拖拽元素的生命周期

 dragstart :当被拖拽元素开始被拖拽时触发

   注意:

    [a]. event.dataTransfer的大部分设置均在这里配置

    [b]. 若调用event.preventDefault()则会阻止拖拽行为,导致后续的拖拽事件不被触发

    [c]. 触发dragstart事件后,其他元素的mousemove,mouseover,mouseenter,mouseleave,mouseout事件均不会被触发了

 drag :当被拖拽元素被拖拽时触发

 dragend :当拖拽行为结束后触发

2. 目标元素的生命周期

  dragenter :当被拖拽元素进入目标元素时触发

  dragover :当被拖拽元素在目标元素上移动时触发

    注意:

     [a]. 可以在这里设置dropEffect的值,事件的默认行为是将dropEffect设置为none

     [b]. 该事件是被拖拽元素在目标元素上移动一段时间后才触发

     [c]. 事件的默认行为是不允许被拖拽元素在其他元素上释放或放置(即无法触发 drop 事件),需要通过 event.preventDefault() 来阻止默认行为才能触发后续的 drop 事件。

   drop :当被拖拽元素在目标元素上,而且释放鼠标左键时触发

    注意:

    [a]. 对于外来的被拖拽元素(超链接、文件、图片源), drop 事件的默认行为是浏览器将当前页面重定向到被拖拽元素所指向的资源上

    [b]. 对文档内部的被拖拽元素,IE10+和Chrome下的默认行为是不作为,而FF得默认行为是新打开一个文档用于访问被拖拽元素所指向的资源

   dragleave :当被拖拽元素离开目标元素时触发。

示例代码:

<div id="drag" style="width:50px;height:50px;background-color:red;">Test</div>
<div id="drop" style="width:100px;height:100px;border:solid 1px red;"></div>
<script type="text/javascript">
  var drag = document.getElementById('drag'), drop = document.getElementById('drop');
  drag.ondragstart = function(evt){
      evt.dataTransfer.setData('Text', 'www.baidu.com');
  };
  drop.ondragover = function(evt){
      evt.preventDefault(); // 这样才能触发drop的drop事件
  };
</script>

3. 整体生命周期

 dragstart -> drag -> dragenter -> dragover ->  dragleave  -> drop -> dragend 

 

八、DnD中最重要的数据传递对象──DataTransfer对象          

  DataTransfer对象用于在配置拖拽行为效果,并且在拖拽过程的各事件间传递数据信息。它存储在事件对象当中,下面我们逐步了解它吧。

1. [object DragEvent]对象

  继承自 [object MouseEvent] 对象,其实就多了个 {DataTransfer} dataTransfer 属性

2. [object DataTransfer]对象详解

  上文说到DataTransfer对象可用于传递数据信息,而数据信息的数据类型被限定为字符串文件类型

  2.1.  effectAllowed 和 dropEffect 属性

     这个两个属性对于初次接触DnD的朋友来说,可谓最令人摸不着头脑的,网上和各书籍上对这两个属性的解释均不全面,下面我试图尽量把它们讲明白。

     effectAllowed 和 dropEffect 最主要的作用是,用于配置拖拽操作过程中鼠标指针的类型以便提示用户后续可执行怎样的操作;其次的作用是,控制 drop 事件的触发与否。

     [a] effectAllowed 

        作用:用于设置被拖拽元素可执行的操作。

        取值范围:

       copy ,限定dropEffect的属性值为copy,否则会鼠标指针为禁止样式

       link ,限定dropEffect的属性值为link,否则会鼠标指针为禁止样式

           move ,限定dropEffect的属性值为move,否则会鼠标指针为禁止样式

           copyLink ,限定dropEffect的属性值为copy和link,否则会鼠标指针为禁止样式

           copyMove ,限定dropEffect的属性值为copy和move,否则会鼠标指针为禁止样式

           linkMove ,限定dropEffect的属性值为link和move,否则会鼠标指针为禁止样式

       all ,允许dropEffect的属性值为任意值

           none ,鼠标指针一直为禁止样式,不管dropEffect的属性值是什么

           uninitialized ,没有限定dropEffect属性的值,效果和 all 一样。

      注意:仅能在 dragstart 事件中设置该属性,其他事件中设置均无效。

      [b].  dropEffect 

     作用:用于设置目标元素将执行的操作,若属性值属于 effectAllowed 范围内,则鼠标指针将显示对应的指针样式,否则则显示禁止的指针样式。

     取值范围:

             copy :被拖拽元素将被复制到目标元素内,若属于 effectAllowed 范围内时,则鼠标指针显示复制的样式,否则则显示禁止的指针样式。

     link :被拖拽元素将以超链接的形式打开资源(具体是否打开资源请参考七、2),若属于 effectAllowed  范围内时,则鼠标指针显示超链接的样式,否则则显示禁止的指针样式。

             move :被拖拽元素将被移动到目标元素内,若属于 effectAllowed   范围内时,则鼠标指针显示移动的样式,否则则显示禁止的指针样式。

             none :被拖拽元素不能在目标元素上作任何操作,一直显示禁止的指针样式。除了文本框外其他元素的默认值均为none

 注意:   

  1. 仅能在 dragover 事件中设置该属性值,其他事件中设置均无效

  2. 当显示禁止的指针样式时,将无法触发目标元素的 drop 事件。

     [c]. 在真实浏览器中的测试结果

     

浏览器 effectAllowed默认值 effectAllowed值
dropEffect默认值


默认使用鼠标指针的效果

IE10+ uninitialized uninitialized copy copy
copyLink none link
copyMove none copy
linkMove none link
all copy link
none    
move move move
link link link
copy copy copy
备注:
1. 无法通过 shift键 切换copyLink,copyMove和linkMove的样式;

2. 若effectAllowed设置为copyLink、copyMove或linkMove,且dropEffect与之对应,则鼠标样式将为dropEffect所设置的样式

Chrome37 all copyLink none copy
copyMove none move
linkMove none move
move move move
link link link
copy copy copy
all copy move
备注:
1. 无法通过 shift键 切换copyLink,copyMove和linkMove的样式;

2. 若effectAllowed设置为copyLink、copyMove或linkMove,且dropEffect与之对应,则鼠标样式将为dropEffect所设置的样式

FF31 for Windows uninitialized copyLink copy copy
copyMove move move
linkMove move move
move move move
link link link
copy copy copy
uninitialized move move
备注:
1. 可通过 shift键 切换copyLink,copyMove和linkMove的样式;

2. 若effectAllowed设置为copyLink、copyMove或linkMove,且dropEffect与之对应,则鼠标样式将为dropEffect所设置的样式

FF33 for Linux 仅能触发dragstart事件,其他事件一律无效,因此不用理会

     

  2.2. 其他属性

   items :数据类型为DataTransferItemList,存储DataTransfer对象中所有的数据项

       注意:1. FF33 for Linux下没有该属性

               2. IE10+没有该属性

     files :数据类型为FileList(IE5~9没有该属性)

       types :数据类型为DOMStringList,存储DataTransfer对象中所有数据项的数据类型

  注意:1. IE5~9下没有该属性

       2. 仅能在dragenter,dragover和drop中获取该属性

 2.3. 方法

        void addElement({HTMLElement} element) :添加一起跟随鼠标移动的元素。仅在 dragstart 事件中调用,Chrome37和IE10+不支持该方法;

        void setDragImage({Element} image, {long} x, {long} y) :设置拖动时跟随鼠标移动的图片,用来替代默认的元素,若image不是图片元素则会元素临时转换为图片;x用于设置图标与鼠标在水平方向上的距离,y设置图标与鼠标在垂直方向上的距离。仅在 dragstart 事件中调用。IE10+不支持该方法;

   注意:

   1. {Element} image必须在DOM树中,而且在渲染树中(即display不为none)为有效元素,否则会导致没有元素跟随鼠标移动;

   2. Chrome37下,若{Element} image为无效元素时,将不会触发dragstart事件后的其他事件。

         boolean setData({DOMString} format, {DOMString} data) :将指定格式的数据赋值给dataTransfer或clipboardData,format值范围为URL、Text(或text)和各种MIME类型,其实Text会被自动映射为text/plain,URL会被自动映射为text/uri-list类型。仅在 dragstart 事件中调用。

     注意:

   1. FF5-是不会将text映射为text/plain,而仅仅支持Text映射为text/plain,因此使用Text或直接使用text/plain

   2. IE10+仅支持Text和URL两种类型,不支持text/plain、text/uri-list等类型

   3.  text/plain类型则不会对数据进行额外处理,而text/uri-list类型则会将数据视为url来使用(体现在当将元素拖拽到OS桌面释放时)

   4.  Chrome和FF支持任意的非空字符串作为format

   5. 当没有填写第二个入参时,则会根据format来删除相应的数据项

   6. 当设置text/uri-list类型的数据时,数据必须带协议名,如http:
//fsjohnhuang.cnblogs.com;若仅写为fsjohnhuang.cnblogs.com,那么dataTransfer将自动弃
除,在`dragstart`事件还能获取到,但在drop事件中将无法获

          DOMString getData({DOMString} format) :从DataTransfer对象或ClipboardData对象中获取指定格式的数据

          void clearData([{DOMString} format]) :从DataTransfer对象或ClipboardData对象中删除指定格式或全部kind值为string的数据。仅在 dragstart 事件中调用,在其他事件中调用会抛InvalidStateError。

 2.4. 数据存储模式

  Read/Write mode:在 dragstart 事件为该模式,可读写数据

  Read-only mode:在 drop 事件为该模式,仅能读取数据

  Protected mode:在其他事件为该模式,仅能枚举数据

 

九、[object DataTransferItemList]类型                  

 readonly unsigined long length 

 getter DataTransferItem(unsigned long index) ,使用方式:items[1]

 deleter void(unsigned long index) ,使用方式:delete items[1],在非Read/Write mode下会报InvalidStateError,而添加数据则不会有问题

 void clear() 

 DataTransferItem add(DOMString data, DOMString type) 

 DataTransferItem add(File data) 

 

十、[object DataTransferItem]类型                    

 readonly attribute DOMString kind ,表示数据的大类型,值范围string和file

 readonly attribute DOMString type ,表示数据的小类型,一般使用mimetype表示,但在Chrome和FF下可以是任意非空字符串

 void getAsString(FunctionStringCallback cb) ,当kind为string时,则只能在Read-only mode和Read/Write mode下才可用。其中cb仅有一个类型为{DOMString}的入参

 File getAsFile() ,当kind为file时,则只能在Read-only mode和Read/Write mode下才可用,没有数据时返回null

 

十一、浏览器支持                               

 IE5~9部分标签支持;

 IE10+、FF、Chrome支持。

 也许大家会好惊讶IE5已经开始支持DnD API啦??其实DnD
API的最初是由IE提出来的,只是后来被HTML5纳入草案而已。大家也许会问在IE5~9上运行上文的代码没有效果,是不是我写错了,下一篇《JS魔
法堂:IE5~9的Drag & Drop
API(http://www.cnblogs.com/fsjohnhuang/p/3980563.html)》我们将一起探讨IE5~9的DnD
API。

 

十二、特征检测是否支持HTML5的DnD API                  

 由于IE5~9的DnD
API与HTML5标准的有差异,因此特征检测变得尤为必要了。下面的代码参考了Modernizr.draganddrop的实现(地
址:https://github.com/Modernizr/Modernizr/blob/master/feature-detects
/draganddrop.js)



var supportDnD = function(){
        var div = document.createElement('div');
        return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
    };

十三、总结                                  

  回到文章最开头的两个示例,会发现使用HTML5 DnD
API实现拖拽效果的代码量并不比HTML4中的少,效果也并不理想(个人水平有限优化也没做好),最让人心酸的是各浏览器在细节上还是有差异的(兼容性
是前端工程师一直的痛啊)。也许大家会说那么DnD API是不是就仅仅好看而不实用呢?其实不然,只是示例把这个特性用到不适合的地方而已。

  HTML5 DnD API最常见的用法就是文件拖拽上传,或把文档内某元素拖到其他元素内或OS桌面上等。这些都是HTML4时代的js很难处理,或者无法处理的。

  尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/3961066.html  ^_^肥仔John

 

十四、参考                                  

http://www.w3school.com.cn/html5/html_5_draganddrop.asp
http://www.cnblogs.com/wpfpizicai/archive/2012/04/07/2436454.html
http://www.kankanews.com/ICkengine/archives/82862.shtml
http://jingyan.baidu.com/article/6dad5075cf6e62a123e36e11.html
http://www.zhangxinxu.com/wordpress/2011/02/html5-drag-drop-%E6%8B%96%E6%8B%BD%E4%B8%8E%E6%8B%96%E6%94%BE%E7%AE%80%E4%BB%8B/
http://my.oschina.net/caixw/blog/102845
http://www.cnblogs.com/birdshome/archive/2006/07/22/Drag_Drop.html
《HTML5实战》第11章、HTML5中元素的拖放
《HTML5用户指南》第8章、拖放
http://msdn.microsoft.com/en-us/library/ff974353(v=vs.85).aspx
《HTML5与CSS3权威指南》4.5.拖放
《论道HTML5》3.3.Drag & Drop API

 

十五、勘误                                  

《HTML5实战》P292 setData的format参数格式包含text/url-list,应更正为text/uri-list

 

十六、书评                                  

《HTML5实战》第11章、HTML5中元素的拖放,这一章感觉就一笔带过,纯属印象派。
《HTML5用户指南》第8章、拖放,除了简单介绍HTML5 DnD API外,还介绍起源和IE上DnD的特点和作者对DnD API不完美的抱怨,比《HTML5实战》更值得拜读。
《HTML5与CSS3权威指南》4.5.拖放,内容,深度与《HTML5实战》相似
《论道HTML5》3.3.Drag & Drop API,对比上述三本书,它提及到使用Modernizr作DnD特征检测,其他基本相似

时间: 2024-09-24 04:49:03

HTML5魔法堂:全面理解Drag & Drop API的相关文章

JS魔法堂:IE5~9的Drag&amp;Drop API

一.前言      < HTML5魔法堂:全面理解Drag & Drop API>中提到从IE5开始已经支持DnD API,但IE5~9与HTML5的API有所不同,下面我们来了解一下吧!   二.IE5~9与HTML5的DnD API的不同点       1. IE5~9DnD API仅对 img元素 . a[href]元素 和 input[type=text]/textarea元素 中被选中的文字有效,且不用设置 draggable="true" ; 而HTML

.Net魔法堂:提取注释生成API文档

一.前言   在多人协作的项目中,除了良好的代码规范外,完整的API文档也相当重要.通过文档我们快速了解系统各模块的实际接口,及其使用场景.使用示例,一定程度上降低沟通成本,和减少后期维护中知识遗失等风险.   对于.Net,我们可以直接将类.方法等的注释直接转为API文档,极大地减少文档维护的工作量,同时也能反向提高大家的注释质量.   下面我们使用.Net唯一的注释生成API文档工具--Sandcastle和Sandcastle Help File Builder来实现API文档自动化吧!

HTML5之拖放Drag &amp;Drop事件的介绍

拖放(Drag &Drop)是一种常见的特性,即抓取对象以后拖到另一个位置.在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放.过去,我们用监听鼠标的Mousedown.Mouseove.Mouseup等事件来不停地获取鼠标的坐标来修改元素的位置,而现在html5原生的Drag &Drop事件(DnD),方便了许多,而且性能也有了提高. 查看演示 下载源码 Internet Explorer 9+.Firefox.Opera 12.Chrome 以及 Safari 5 支持拖放.

CSS魔法堂:深入理解line-height和vertical-align

前言 一直听说line-height是指两行文本的基线间的距离,然后又说行高等于行距,最近还听说有个叫行间距的家伙,@张鑫旭还说line-height和vertical-align基情四射,贵圈真乱啊......于是通过本篇来一探究竟:) line-height到底有多height? 行距.行间距傻傻分不清  首先看看"有道词典"的解析! Leading = Line Space + Font Size(即是 行距 = 行间距 + 字体大小) Leading: 指相邻文本行间上一个文本

JS魔法堂:精确判断IE的文档模式by特征嗅探

一.前言   苦逼的前端攻城狮都深受浏览器兼容之苦,再完成每一项功能前都要左顾右盼,生怕浏览器不支持某个API,生怕原生API内含臭虫因此判断浏览器类型和版本号成了不可绕过的一道关卡,而特征嗅探是继浏览器探测后另一利器处理上述问题.   二.何为特征嗅探 从前我们都是通过对navigator.userAgent或navigator.appVersion两个属性值进行特定字符串匹配和萃取来区 分浏览器类型和获取版本号的.但随着IE8提供可选的文档兼容性模式设置和各种加壳浏览器的出现,导致无法通过n

JS魔法堂:属性、特性,傻傻分不清楚

或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById("dummy"); el.hello = "test"; console.log(el.getAttribute("hello")); // IE67下输出test,其他浏览器输出null   "搞毛啊?",苦逼的Jser对着浏览器大呼一声.然后就用下面蹩脚的方式草草处理掉了. function getAttr(el, p

JS魔法堂:LINK元素深入详解

一.前言   我们一般使用方式为 <link type="text/css" rel="stylesheet" href="text.css"> 来引入外部层叠式样式文件,但LINK元素各属性的具体含义.资源加载行为等方面却了解不多,本文打算稍微深入一下.   由于内容较多,特设目录一坨:   二.到底有没有结束标签?  三.普通属性介绍  四.属性disabled详解    1. Attribute和Property的disable

JS魔法堂:那些困扰你的DOM集合类型

一.前言 大家先看看下面的js,猜猜结果会怎样吧! 可选答案: ①. 获取id属性值为id的节点元素 ②. 抛namedItem is undefined的异常 var nodes = document.getElementsByName('dummyName'); var node = nodes.namedItem('id'); 答案是两种都有可能哦!document.getElementsByName在Chrome和FF30.0中返回NodeList(木有namedItem方法的),在IE

Java魔法堂:类加载器入了个门

一.前言   <Java魔法堂:类加载机制入了个门>中提及整个类加载流程中只有加载阶段作为码农的我们可以入手干预,其余均由JVM处理.本文将记录加载阶段的核心组件--类加载器的相关信息,以便日后查阅.若有纰漏请大家指正,谢谢.   注意:以下内容基于JDK7和HotSpot VM.   二.类加载器种类及其关系 从上图可知Java主要有4种类加载器 1. Bootstrap ClassLoader(引导类加载器):作为JVM的一部分无法在应用程序中直接引用,由C/C++实现(其他JVM可能通过