• 兼容所有浏览器的拖拽交互


    目录:

    1. 用H5方法实现拖拽交互
    2. 自定义事件
    3. 自定义拖拽事件
    4. 实现兼容所有浏览器的拖拽交互

    跟着教程用H5实现了一个简单的拖拽,左右两个白盒子是容器,两边的红盒子可以任意拖拽。

    满足以下两个要求:

    • 被拖起来的盒子变成黄色,并且在原容器中消失,跟随鼠标移动。
    • 被拖拽的盒子进入容器时,容器会变颜色,离开时恢复原来的颜色。
    • 拖拽释放后,添加到准确的位置。

    HTML+CSS为:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>拖动</title>
    </head>
    <style>
        body{
            background-color: #ccc;
        }
        .container {
            width: 200px;
            height: 800px;
            background-color: #fff;
            border: 1px solid #000;
            margin: 50px;
            float: left;
        }
        .box {
            width: 200px;
            height: 80px;
            background-color: #f00;
            border: 1px solid #000;
        }
        .light {
            background-color: #f9f;
        }
        .move {
            background-color: #ffff73;
        }
        .hide {
            display: none;
        }
    </style>
    <body>
    <div class="wrap">
        <div class="container">
            <div class="box">1</div>
            <div class="box">2</div>
            <div class="box">3</div>
            <div class="box">4</div>
        </div><!--container结束-->
        <div class="container">
            <div class="box">5</div>
            <div class="box">6</div>
            <div class="box">7</div>
        </div><!--container结束-->
    </div><!--wrap结束-->

           <script type="text/javascript" src="js/util.js"></script> 

         <script type="text/javascript" src="js/dragAnddrop.js"></script>
    </body>
    </html>

    (util.js中是一些平时经常会用到的方法,像下面会出现的$.on( )用于接受一个选择器,然后在其表示的节点上绑定事件。$.getElements( )负责选出符合接收到的选择器的所有元素。)

    看教程之前,我的代码大致是这样的:

    window.onload=function(){
        var boxes=getElements(".box");
        //设置拖动目标可以被拖动
        each(me.box,function(item,index){
            item.draggable=true;
        });
        //获取拖动目标,并为其添加样式
        $.on(".wrap","dragstart",function(e){
            var e=e||window.event,
                target=e.target||e.srcElement;
            if (hasClass(target,"box")) {
                e.dataTransfer.setData("text/plain",".move");
            }
        });
            //其他功能
    }

    然后我看到了教程中这样的代码:

    (function () {
        var dnd = {
          // 初始化
          init: function () {
            var me = this;
            me.src = document.querySelector('#demo1-src');
            me.panelList = document.querySelector('.panel-list');
    
            // 为拖拽源监听dragstart,设置关联数据
            me.src.addEventListener('dragstart', me.onDragStart, false);
    
            //省略
          onDragStart: function (e) {
            e.dataTransfer.setData('text/plain', 'demo1-src');
          },
          //省略
        dnd.init();
      }());

    顿时觉得自己写了一坨屎。不过还好,终于见识到了传说中的面向对象。

    在用H5实现拖拽交互的过程中,我遇到一个问题:

    为drop添加事件处理程序的时候,要用appendChild方法将被拖拽的盒子添加到容器中去,那么要怎么获取到被拖拽的元素呢?

    我先想到可以在dragstart事件处理程序中把被拖拽的元素保存在一个变量里,然后再drop的事件处理程序访问它。但是很遗憾,并不能访问到。想一想,这是因为变量被声明之后的值是undefined,他在dragstart事件处理程序中被赋值,结束之后这个值就已经失效了,所以drop的事件处理程序中访问到的变量值是undefined。

    然后我想到了,在事件处理程序中想要获得信息,可以通过传入的事件对象,想到这里,之前看的云里雾里的dataTransfer对象就派上用场了。可以在dragstart事件处理程序中将为被拖拽的对象添加的class通过setData()方法传递给drop,这样就可以获取到他了。

    最终写好的代码如下:

    window.onload=function(){
        var dragdrop={
            //初始化
            init:function(){
                var me=this;
                me.box=getElements(".box");
                //设置拖动目标可以被拖动
                each(me.box,function(item,index){
                    item.draggable=true;
                });
                //获取拖动目标,并为其添加样式
                $.on(".wrap","dragstart",me.dragStart);
                //让拖动目标在拖起来的时候在原容器中消失
                $.on(".wrap","drag",me.Drag);
                //松开的时候恢复原状
                $.on(".wrap","dragend",me.dragEnd);
                //监听放置目标的dragenter事件,添加视觉效果
                $.on(".wrap","dragenter",me.dragEnter);
                //设置放置目标
                $.on(".wrap","dragover",me.prevent);
                //取消视觉效果
                $.on(".wrap","dragleave",me.dragLeave);
                //在拖放目标上处理
                $.on(".wrap","drop",me.dragDrop);
            },
            dragStart:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (hasClass(target,"box")) {
                    e.dataTransfer.setData("text/plain",".move");
                    addClass(target,"move");
                }
            },
            Drag:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (hasClass(target,"box")) {
                    addClass(target,"hide");
                }
            },
            dragEnd:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (hasClass(target,"box")) {
                    removeClass(target,"hide");
                    removeClass(target,"move");
                }
            },
            dragEnter:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (hasClass(target,"container")) {
                    addClass(target,"light");
                }
            },
            prevent:function(e){
                $.prevent(e);
            },
            dragLeave:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (hasClass(target,"container")) {
                    removeClass(target,"light");
                }
            },
            dragDrop:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (hasClass(target,"container")) {
                    var dragging=$(e.dataTransfer.getData("text/plain"));
                    removeClass(dragging,"move");
                    removeClass(target,"light");
                    target.appendChild(dragging);
                }
            },
        }
        dragdrop.init();
    }

    虽然还没有很深刻的体会到这种面向对象写法的好处,但还是模仿着写了。

    接下来就要开始照顾不支持H5的宝宝们了。

    一开始就被一系列的问题卡住,他怎么动起来?什么时候让他动起来?怎么让他跟着鼠标走?他怎么回去?怎么给它绑定事件处理程序?

    前两个问题还能勉强想出来,当鼠标按下的时候,可以给他设置position:absolute让他动起来,然后让他的left和top和mousedown事件的鼠标坐标相同就可以了。

    后几个问题就真的束手无策了。

    在《JavaScript高级程序设计》中找到答案,发现这件事情真的没那么简单。

    最本质的,要深刻地理解事件是怎么回事。

    事件是一种叫做观察者的设计模式,这是一种创建松散耦合代码的技术。对象可以发布事件,用来表示在该对象生命周期中某个有趣的时刻到了。然后其他对象可以观察该对象,等待这些有趣的时刻到来并通过运行代码来响应。

    意思就是说,事件是一个对象发出的信号,他邀请别人一起来庆祝他重要的时刻,不管有没有人愿意来,他都可以发出信号。

    那么,他要怎样发出信号呢? 通过 函数调用 很容易就可以实现对象之间的通信。

    有行为就需要有管理机制,得到一个名字,检测其对应的函数,执行函数。所以就需要一个对象来进行管理。

    函数的调用需要一些代码,需要函数名。所以这个对象中应该保存着函数名表示事件类型,还要保存该类型相应的代码,所以他还需要一个个方法为其添加事件类型和处理函数,还要有一个让函数中的代码执行的方法,这个方法读取函数名,然后执行这个函数名对应的代码。可以添加就要可以删除,所以还需要一个负责删除处理程序的方法。

    所以,这个对象应该长这样:

    {

    事件类型和他的代码们:

    {type1:[fun1,fun2...]

      type2:[fun1,fun2,..]

      .....}

    接待员:为对象添加type和相应fun。

    执行官:接收一个type执行相应代码。

    清理员:接收一个type和他想删除的fun,为其删掉这个fun。

    }

     用JavaScript实现就长下面这样:

    function eventTarget(){
        this.handlers={};
    }
    
    eventTarget.prototype={
        constructor:eventTarget,
        addHandler:function(type,handler){
            if (typeof this.handlers[type]=="undefined") {
                this.handlers[type]=[];
            }
            this.handlers[type].push(handler);
        },
    
        fire:function(e){
            var handlers=this.handlers[e.type]
            if (isArray(handlers)) {
                for (var i = 0,len = handlers.length;i<len; i++) {
                    handlers[i](e);
                }
            }
        },
    
        removeHandler:function(type,handler){
            if (isArray(this.handlers[type])) {
                removeItem(this.handlers[type],handler);
            }
        },
    };

    用这种构造函数+原型的方式,就是为了自定义的事件可以继承他的方法,并拥有自己的事件类型。

    有了这个完美的事件管理机制,就可以自定义拖拽事件对象了。

    按照H5的思路,他应该可以触发这6种事件:dragstart、drag、dragend、dragenter、dragleave和drop。

    首先,他如何触发dragstart?什么时候应该触发dragstart?

    拖拽的本质就是,鼠标在一个元素上按下不松开,挪动鼠标,放到另一个地方,松开。

    听起来好像很熟悉,就是我们熟悉的mousedown、mousemove和mouseup嘛。

    所以,当元素上发生mousedown的时候,就触发dragstart事件,移动的时候触发drag,移动到目标元素里面的时候触发dragenter,移出去的时候触发dragleave,松开的时候要是在目标元素里面就触发drop,然后触发dragend(因为不在里面的话要回到原位)。

    如果要绑定事件的话,就要知道绑定在哪里,因为事先不知道要被绑定的元素,所以绑定在document上,让每个DOM对象都有机会成为被拖拽的和放置目标。然后指定筛选条件,在指定的满足条件的对象上面触发事件。

    那么,如何指定被拖拽对象和放置目标呢?

    还是模仿H5,他通过设置draggable属性和阻止浏览器默认行为,我们也可以通过添加一个自定义属性或者类名,来判别目标对象。

    想明白这些之后,就可以开始写处理程序了,解决了重重问题之后,最后的对象是这样的:

    //自定义拖动事件(和HTML的class属性耦合)
    var DragDrop=function(){
        var dragdrop=new eventTarget(),
            dragging=null,  
            x=0,y=0,
            border_r,border_l,border_top,border_btm,
            left,right,top,bottom;
        
        function handle(e){
            var e=e||window.event,
                target=e.target||e.srcElement,
                drops=getElements(".dropable");  //问题1
            switch(e.type){
                case "mousedown":
                    if (hasClass(target,"draggable")) {
                        dragging=target;
                        x=e.clientX-target.offsetLeft;
                        y=e.clientY-target.offsetTop;
                        dragdrop.fire({
                            type:"dragstart",
                            target:dragging,
                            x:e.clientX,
                            y:e.clientY
                        });
                    }
                    break;
                case "mousemove":
                    if (dragging!==null) {
                        dragging.style.left=e.clientX-x+"px";
                        dragging.style.top=e.clientY-y+"px";
                        dragdrop.fire({
                            type:"drag",
                            target:dragging,
                            x:e.clientX,
                            y:e.clientY
                        });
                        if (drops[0]) {
                            for (var i = 0; i < drops.length; i++) {
                            border_l=dragging.offsetLeft;
                            border_r=parseInt(getCSS(dragging,"width"))+border_l;  //问题2
                            border_top=dragging.offsetTop;
                            border_btm=parseInt(getCSS(dragging,"height"))+border_top;
                            left=drops[i].offsetLeft;
                            right=parseInt(getCSS(drops[i],"width"))+left;
                            top=drops[i].offsetTop;
                            bottom=parseInt(getCSS(drops[i],"height"))+top;
                            if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){
                                dragdrop.fire({
                                    type:"dragenter",
                                    target:drops[i]
                                });
                                }else{
                                    dragdrop.fire({
                                        type:"dragleave",
                                        target:drops[i]
                                    });
                                }
                            }
                        }
                    }
                    break;
                case "mouseup":
                    if (drops[0]&&dragging) {
                        for (var i = 0; i < drops.length; i++) {
                            dragWidth=parseInt(getCSS(dragging,"width"));
                            border_r=dragWidth+dragging.offsetLeft;
                            border_l=dragging.offsetLeft;
                            left=drops[i].offsetLeft;
                            right=drops[i].offsetLeft+parseInt(getCSS(drops[i],"width"));
                            if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){  //问题3
                                dragdrop.fire({
                                    type:"drop",
                                    target:drops[i],
                                    dragging:dragging
                                });
                            break;
                            }
                        }
                    }
                    dragdrop.fire({
                        type:"dragend",
                        target:dragging,
                        x:e.clientX,
                        y:e.clientY
                    });
                    dragging=null;
                    break;
            }
        };
        dragdrop.enable=function(){
            $.add(document,"mousedown",handle);
            $.add(document,"mousemove",handle);
            $.add(document,"mouseup",handle);
        };
        dragdrop.disable=function(){
            $.remove(document,"mousedown",handle);
            $.remove(document,"mousemove",handle);
            $.remove(document,"mouseup",handle);
        };
        return dragdrop;
    }

    问题1:

    最开始的时候,我是不知道该怎么将被拖拽对象和目标对象分开的,我一直想,当感受到拖拽的时候就让事件的target变成被拖拽的元素,当感受到有东西改过来时让事件的target变成目标对象,当我尝试着把dragenter事件让mouseenter来触发时,失望的发现,鼠标上拖着东西的时候是无法触发mouseenter的。

    然后我想到,既然只能获得被拖拽的对象,也没有想mousedown那样的事件可以来获取放置目标,那就换个思路。通过class来获取,毕竟在我心中class是个万能的东西。所以我的逻辑就是,获取到所有class=droppable的对象,判断他们是否被拖动元素覆盖,是的话就触发dragenter,不是的话就触发dragleave。(这也就导致了问题3。)

    问题2:

    我想到的判断拖拽元素是否在目标元素上方的方法是,看被拖动元素是否有两条边线在目标元素之内。这就需要获取拖拽元素和目标元素的width。

    而用node.style.width获取不到。查了一下发现,这个方法只能获取到写在标签里面的样式。想要获取CSS中的样式,需要用DOM2级样式中定义的document.defaultView.getComputerStyle()和IE的obj.currentStyle。所以就写了一个getCSS方法,代码如下:

    //获得元素的CSS样式
    function getCSS(ele,name){
        if (ele) {
            return document.defaultView.getComputedStyle?
                document.defaultView.getComputedStyle(ele,null)[name]:ele.currentStyle[name];
        }
    }

    问题3:

    由于我上面判断目标对象的逻辑,被拖拽的元素会更容易drop进第一个带有droppable的容器里面。这个问题还有待解决。

    定义好拖拽事件对象之后,就可以为其绑定处理程序了。

    这时候就体现出之前面向对象写法的好处了:①他将所有事件处理函数都变成对象自身的方法,减少了很多游离再全局中的变量。②这些方法只有他自己能调用,外部不需要知道这里会发生什么,只需要知道他能做这些事情就够了。

    这样的写法,让一切变得非常井然有序,逻辑清晰。

    因为他们处理的方法是不同的,所以事件处理程序中的执行代码会有些差异,需要判断一下,不然会有冲突。

    到这里,已经可以实现我想要的功能了,而且还没有发现什么重大的问题。所以暂时先写成这个样子啦。

    虽然一直很嫌弃不支持新方法的浏览器,尤其是IE。但是这次要好好的感谢一下他,让我更深刻的了解了事件,并且让我见识到了JavaScript如此强大的函数,它可以创造无限可能。

    完整代码(https://github.com/mamengyi/Baidu/tree/master/2015_Spring/task0002/%E6%8B%96%E6%8B%BD%E4%BA%A4%E4%BA%92)

    //自定义事件
    function eventTarget(){
        this.handlers={};
    }
    
    eventTarget.prototype={
        constructor:eventTarget,
        addHandler:function(type,handler){
            if (typeof this.handlers[type]=="undefined") {
                this.handlers[type]=[];
            }
            this.handlers[type].push(handler);
        },
    
        fire:function(e){
            var handlers=this.handlers[e.type]
            if (isArray(handlers)) {
                for (var i = 0,len = handlers.length;i<len; i++) {
                    handlers[i](e);
                }
            }
        },
    
        removeHandler:function(type,handler){
            if (isArray(this.handlers[type])) {
                removeItem(this.handlers[type],handler);
            }
        },
    };
    
    
    //自定义拖动事件(和HTML的class属性耦合)
    var DragDrop=function(){
        var dragdrop=new eventTarget(),
            dragging=null,
            x=0,y=0,
            border_r,border_l,border_top,border_btm,
            left,right,top,bottom;
        
        function handle(e){
            var e=e||window.event,
                target=e.target||e.srcElement,
                drops=getElements(".dropable");
            switch(e.type){
                case "mousedown":
                    if (hasClass(target,"draggable")) {
                        dragging=target;
                        x=e.clientX-target.offsetLeft;
                        y=e.clientY-target.offsetTop;
                        dragdrop.fire({
                            type:"dragstart",
                            target:dragging,
                            x:e.clientX,
                            y:e.clientY
                        });
                    }
                    break;
                case "mousemove":
                    if (dragging!==null) {
                        dragging.style.left=e.clientX-x+"px";
                        dragging.style.top=e.clientY-y+"px";
                        dragdrop.fire({
                            type:"drag",
                            target:dragging,
                            x:e.clientX,
                            y:e.clientY
                        });
                        if (drops[0]) {
                            for (var i = 0; i < drops.length; i++) {
                            border_l=dragging.offsetLeft;
                            border_r=parseInt(getCSS(dragging,"width"))+border_l;
                            border_top=dragging.offsetTop;
                            border_btm=parseInt(getCSS(dragging,"height"))+border_top;
                            left=drops[i].offsetLeft;
                            right=parseInt(getCSS(drops[i],"width"))+left;
                            top=drops[i].offsetTop;
                            bottom=parseInt(getCSS(drops[i],"height"))+top;
                            if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){
                                dragdrop.fire({
                                    type:"dragenter",
                                    target:drops[i]
                                });
                                }else{
                                    dragdrop.fire({
                                        type:"dragleave",
                                        target:drops[i]
                                    });
                                }
                            }
                        }
                    }
                    break;
                case "mouseup":
                    if (drops[0]&&dragging) {
                        for (var i = 0; i < drops.length; i++) {
                            dragWidth=parseInt(getCSS(dragging,"width"));
                            border_r=dragWidth+dragging.offsetLeft;
                            border_l=dragging.offsetLeft;
                            left=drops[i].offsetLeft;
                            right=drops[i].offsetLeft+parseInt(getCSS(drops[i],"width"));
                            if(border_r>left&&border_l<right&&border_top<bottom&&border_btm>top){  //会更容易drop进第一个盒子里。
                                dragdrop.fire({
                                    type:"drop",
                                    target:drops[i],
                                    dragging:dragging
                                });
                            break;
                            }
                        }
                    }
                    dragdrop.fire({
                        type:"dragend",
                        target:dragging,
                        x:e.clientX,
                        y:e.clientY
                    });
                    dragging=null;
                    break;
            }
        };
        dragdrop.enable=function(){
            $.add(document,"mousedown",handle);
            $.add(document,"mousemove",handle);
            $.add(document,"mouseup",handle);
        };
        dragdrop.disable=function(){
            $.remove(document,"mousedown",handle);
            $.remove(document,"mousemove",handle);
            $.remove(document,"mouseup",handle);
        };
        return dragdrop;
    }
    
    
    
    //拖动
    window.onload=function(){
        var dragdrop={
            //初始化
            inith5:function(){
                var me=this;
                me.box=getElements(".box");
                //设置拖动目标可以被拖动
                each(me.box,function(item,index){
                    item.draggable=true;
                });
                //获取拖动目标,并为其添加样式
                $.on(".wrap","dragstart",me.dragStart);
                //让拖动目标在拖起来的时候在原容器中消失
                $.on(".wrap","drag",me.Drag);
                //松开的时候恢复原状
                $.on(".wrap","dragend",me.dragEnd);
                //监听放置目标的dragenter事件,添加视觉效果
                $.on(".wrap","dragenter",me.dragEnter);
                //设置放置目标
                $.on(".wrap","dragover",me.prevent);
                //取消视觉效果
                $.on(".wrap","dragleave",me.dragLeave);
                //在拖放目标上处理
                $.on(".wrap","drop",me.dragDrop);
            },
            init:function(){
                var me=this,
                    dragevent=new DragDrop();
                dragevent.enable();
                //设置拖动目标可以被拖动
                me.box=getElements(".box");
                each(me.box,function(item,index){
                    addClass(item,"draggable");
                });
                //获取拖动目标,并为其添加样式
                dragevent.addHandler("dragstart",me.dragStart);
                //松开的时候恢复原状
                dragevent.addHandler("dragend",me.dragEnd);
                //监听放置目标的dragenter事件,添加视觉效果
                dragevent.addHandler("dragenter",me.dragEnter);
                //设置放置目标
                me.container=getElements(".container");
                each(me.container,function(item,index){
                    addClass(item,"dropable");
                });
                //取消视觉效果
                dragevent.addHandler("dragleave",me.dragLeave);
                //在拖放目标上处理
                dragevent.addHandler("drop",me.dragDrop);
            },
            dragStart:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (hasClass(target,"box")) {
                    if (e.dataTransfer) {
                        e.dataTransfer.setData("text/plain",".move");
                        addClass(target,"move");
                    }else{
                        addClass(target,"moving");
                    }
                }
            },
            Drag:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (e.dataTransfer&&hasClass(target,"box")) {
                    addClass(target,"hide");
                }
            },
            dragEnd:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (e.dataTransfer&&hasClass(target,"box")) {
                    removeClass(target,"hide");
                    removeClass(target,"move");
                }else{
                    removeClass(target,"moving");
                }
            },
            dragEnter:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (hasClass(target,"container")) {
                    addClass(target,"light");
                }
            },
            prevent:function(e){
                $.prevent(e);
            },
            dragLeave:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (hasClass(target,"container")) {
                    removeClass(target,"light");
                }
            },
            dragDrop:function(e){
                var e=e||window.event,
                    target=e.target||e.srcElement;
                if (e.dataTransfer&&hasClass(target,"container")) {
                    var dragging=$(e.dataTransfer.getData("text/plain"));
                    removeClass(dragging,"move");
                    removeClass(target,"light");
                    target.appendChild(dragging);
                }else if (e.dragging) {
                    var lights=getElements(".light"),
                        len=lights.length;
                    for (var i = 0; i < len; i++) {
                        removeClass(lights[0],"light"); //注意这里是一个NodeList
                    }
                    removeClass(e.dragging,"moving");
                    target.appendChild(e.dragging);
                }
            },
        }
        if(supportDrag()){
            dragdrop.inith5();
        }else{
            dragdrop.init();
        }
    }

    util:

    //对数组(类数组对象)的每项都执行fn(item,index)
    function each(arr,fn){
        for(var i = 0 , len = arr.length ; i<len ; i++){
            fn(arr[i],i);
        }
    }
    //DOM元素选择器
    function getElements(selector){
        //类选择器,返回全部项
        if(/.((?:[wu00c0-uFFFF-]|\.)+)/.test(selector)){
            if(document.getElementsByClassName){
                return document.getElementsByClassName(selector.slice(1,selector.length));
            }
            var nodes = document.all ? document.all : document.getElementsByTagName('*');
            var arr=[];//用来保存符合的className;    
            for(var i=0;i<nodes.length;i++){
                if(hasClass(nodes[i],selector.slice(1,selector.length))){
                    arr.push(nodes[i]);
                }
            }
            return arr;
        }
    
        //ID选择器
        if(/#((?:[wu00c0-uFFFF-]|\.)+)/.test(selector)){
            return document.getElementById(selector.slice(1,selector.length));
        }
    
    
        //tag选择器
        if(/^((?:[wu00c0-uFFFF-]|\.)+)/.test(selector)){
            return document.getElementsByTagName(selector);
        }
    
        //属性选择器
        if(/^[[A-Za-z0-9_-S]+]$/.test(selector)){
            selector = selector.slice(1,selector.length-1);
            var eles = document.getElementsByTagName("*");
            selector = selector.split("=");
            var att = selector[0];
            var value = selector[1];
            var arr = []; 
            if (value) {
                for (var i = 0; i < eles.length; i++) {
                    if(eles[i].getAttribute(att)==value){
                       arr.push(eles[i]);
                    } 
                }
            }else{
                for (var i = 0; i < eles.length; i++) {
                    if(eles[i].getAttribute(att)){
                        arr.push(eles[i]);
                    } 
                }
            }
            return arr;
        }
    }
    function $(selector){
        var all=selector.split(/s+/);
        var result = [],rooot=[document];
        for (var i = 0; i < all.length; i++) {
            var type=all[i][0];
            switch(type){
            //ID
            case "#" :
                for (var j = 0; j < rooot.length; j++) {
                    var ele=rooot[j].getElementById(all[i].slice(1));
                    if (ele) {
                        result.push(ele);
                    }
                }
                break;
            
            //class
            case ".":
                for (var j = 0; j < rooot.length; j++) {
                    if (document.getElementsByClassName) {
                        var eles=rooot[j].getElementsByClassName(all[i].slice(1));
                        if (eles) {
                            result=result.concat(Array.prototype.slice.call(eles));
                        }
                    }else{
                        var arr = rooot[j].getElementsByTagName("*");
                        for (var i = 0; i < arr.length; i++) {
                            if (hasClass(arr[i], className)) {
                                result.push(arr[i]);
                            }
                        }
                    }
                }
                break;
            //属性
            case "[":
                var att = all[i].slice(1,all[i].length-1).split("=");
                var key = att[0],value=att[1];
                for (var j = 0; j < rooot.length; j++) {
                    var eles=rooot[j].getElementsByTagName("*");
                    for (var i = 0; i < eles.length; i++) {
                        if (value) {
                            for (var i = 0; i < eles.length; i++) {
                                if(eles[i].getAttribute(key)==value){
                                    result.push(eles[i]);
                                }
                            }
                        }else{
                            for (var i = 0; i < eles.length; i++) {
                                if(eles[i].getAttribute(key)){
                                    result.push(eles[i]);
                                }
                            }
                        }
                    }
                }
                break;
            //tag
            default:
                for (var j = 0; j < rooot.length; j++) {
                    eles=rooot[j].getElementsByTagName(all[i]);
                    if (eles) {
                        result=result.concat(Array.prototype.slice.call(eles));
                    }
                }
            }
            rooot=result;
            result=[];   
        }
        return rooot[0];
    }
    //检查ele是否有className
    function hasClass(ele,className){
        if (ele&&ele.className) {
            var classes=ele.className.split(/s+/);//这里必须要切成数组之后再判断
            if(classes.indexOf(className)!=-1){
                return true;
            } 
        }
        return false;
    }
    
    // 为element增加一个样式名为newClassName的新样式
    function addClass(ele,newClass){
        if (!hasClass(ele,newClass)) {
            ele.className=ele.className?[ele.className,newClass].join(" "):newClass;
        }
    }
    
    // 移除element中的样式oldClassName
    function removeClass(ele,oldClass){
        if (hasClass(ele,oldClass)) {
            var arr = ele.className.split(/s+/);
            for (var i = 0; i < arr.length; i++) {
                if(arr[i]===oldClass){
                    arr.splice(i,1);
                    break;
                }
            }
            ele.className=arr.join(" ");
        }
    }
    //获得元素的CSS样式
    function getCSS(ele,name){
        if (ele) {
            return document.defaultView.getComputedStyle?
                document.defaultView.getComputedStyle(ele,null)[name]:ele.currentStyle[name];
        }
    }
    //添加事件
    function addEvent(selector,event,listener){
        var ele=$(selector);
        if(ele.addEventListener){
            ele.addEventListener(event,listener,false);
        }else{
            ele.attachEvent("on"+event,listener);
        }
    }
    //添加事件(给节点)
    function addEventToNode(ele,event,listener){
        if(ele.addEventListener){
            ele.addEventListener(event,listener,false);
        }else{
            ele.attachEvent("on"+event,listener);
        }
    }
    //移除事件
    function removeEvent(selector,event,listener){
        var ele=$(selector);
        if(ele.removeEventListener){
            ele.removeEventListener(event,listener,false);
        }else{
            ele.detachEvent("on"+event,listener);
        }
    }
    function removeNodeEvent(ele,event,listener){
        if(ele.removeEventListener){
            ele.removeEventListener(event,listener,false);
        }else{
            ele.detachEvent("on"+event,listener);
        }
    }

    //阻止浏览器默认行为
    function preventDefault(e){
    if (e&&e.preventDefault) {
    e.preventDefault();
    }else{
    e.returnValue=false;
    }
    return false;
    }
    $.prevent=preventDefault;

    $.on = addEvent;
    $.add = addEventToNode;
    $.un = removeEvent;
    $.remove=removeNodeEvent;

    //判断是否支持ondrag事件

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

    参考:

    教程:http://qiudeqing.com/html5/2015/05/17/drag-and-drop.html

  • 相关阅读:
    Spring中Model,ModelMap以及ModelAndView之间的区别
    ssm框架中Controller层的junit测试_我改
    Controller、Service、Dao进行Junit单元
    ssm controller层 junit单元测试
    spring常用注解
    Spring MVC测试框架
    ssm框架junit简单测试_我写
    spring注入时报错::No qualifying bean of type 'xxx.xxMapper'
    Eclipse 报 "The builder launch configuration could not be found" 错误
    IIS负载均衡-Application Request Route详解第一篇: ARR介绍(转载)
  • 原文地址:https://www.cnblogs.com/LiveWithIt/p/5906692.html
Copyright © 2020-2023  润新知