类似Google ig和live.com的自由拖动窗口功能
代码写的比较复杂,我研究一上午了没全弄清楚,先留下来以便研究并为己用。

原文: How to Drag and Drop in JavaScript

我只选择了我想研究的部份,有兴趣的去看原文。

HTML部份:
<SCRIPT
      src="drag_drop.js"
      type=text/javascript></SCRIPT>
<STYLE type=text/css>LI {
    MARGIN-BOTTOM: 10px
}
OL {
    MARGIN-TOP: 5px
}
.DragContainer {
    BORDER-RIGHT: #669999 2px solid; PADDING-RIGHT: 5px; BORDER-TOP: #669999 2px solid; PADDING-LEFT: 5px; FLOAT: left; PADDING-BOTTOM: 0px; MARGIN: 3px; BORDER-LEFT: #669999 2px solid; WIDTH: 100px; PADDING-TOP: 5px; BORDER-BOTTOM: #669999 2px solid
}
.OverDragContainer {
    BORDER-RIGHT: #669999 2px solid; PADDING-RIGHT: 5px; BORDER-TOP: #669999 2px solid; PADDING-LEFT: 5px; FLOAT: left; PADDING-BOTTOM: 0px; MARGIN: 3px; BORDER-LEFT: #669999 2px solid; WIDTH: 100px; PADDING-TOP: 5px; BORDER-BOTTOM: #669999 2px solid
}
.OverDragContainer {
    BACKGROUND-COLOR: #eee
}
.DragBox {
    BORDER-RIGHT: #000 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #000 1px solid; PADDING-LEFT: 2px; FONT-SIZE: 10px; MARGIN-BOTTOM: 5px; PADDING-BOTTOM: 2px; BORDER-LEFT: #000 1px solid; WIDTH: 94px; CURSOR: pointer; PADDING-TOP: 2px; BORDER-BOTTOM: #000 1px solid; FONT-FAMILY: verdana, tahoma, arial; BACKGROUND-COLOR: #eee
}
.OverDragBox {
    BORDER-RIGHT: #000 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #000 1px solid; PADDING-LEFT: 2px; FONT-SIZE: 10px; MARGIN-BOTTOM: 5px; PADDING-BOTTOM: 2px; BORDER-LEFT: #000 1px solid; WIDTH: 94px; CURSOR: pointer; PADDING-TOP: 2px; BORDER-BOTTOM: #000 1px solid; FONT-FAMILY: verdana, tahoma, arial; BACKGROUND-COLOR: #eee
}
.DragDragBox {
    BORDER-RIGHT: #000 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #000 1px solid; PADDING-LEFT: 2px; FONT-SIZE: 10px; MARGIN-BOTTOM: 5px; PADDING-BOTTOM: 2px; BORDER-LEFT: #000 1px solid; WIDTH: 94px; CURSOR: pointer; PADDING-TOP: 2px; BORDER-BOTTOM: #000 1px solid; FONT-FAMILY: verdana, tahoma, arial; BACKGROUND-COLOR: #eee
}
.miniDragBox {
    BORDER-RIGHT: #000 1px solid; PADDING-RIGHT: 2px; BORDER-TOP: #000 1px solid; PADDING-LEFT: 2px; FONT-SIZE: 10px; MARGIN-BOTTOM: 5px; PADDING-BOTTOM: 2px; BORDER-LEFT: #000 1px solid; WIDTH: 94px; CURSOR: pointer; PADDING-TOP: 2px; BORDER-BOTTOM: #000 1px solid; FONT-FAMILY: verdana, tahoma, arial; BACKGROUND-COLOR: #eee
}
.OverDragBox {
    BACKGROUND-COLOR: #ffff99
}
.DragDragBox {
    BACKGROUND-COLOR: #ffff99
}
.DragDragBox {
    FILTER: alpha(opacity=50); BACKGROUND-COLOR: #ff99cc
}
LEGEND {
    FONT-WEIGHT: bold; FONT-SIZE: 12px; COLOR: #666699; FONT-FAMILY: verdana, tahoma, arial
}
FIELDSET {
    PADDING-RIGHT: 3px; PADDING-LEFT: 3px; PADDING-BOTTOM: 3px; PADDING-TOP: 3px
}
.History {
    FONT-SIZE: 10px; OVERFLOW: auto; WIDTH: 100%; FONT-FAMILY: verdana, tahoma, arial; HEIGHT: 82px
}
#DragContainer8 {
    BORDER-RIGHT: #669999 1px solid; PADDING-RIGHT: 0px; BORDER-TOP: #669999 1px solid; PADDING-LEFT: 5px; PADDING-BOTTOM: 0px; BORDER-LEFT: #669999 1px solid; WIDTH: 110px; PADDING-TOP: 5px; BORDER-BOTTOM: #669999 1px solid; HEIGHT: 110px
}
.miniDragBox {
    FLOAT: left; MARGIN: 0px 5px 5px 0px; WIDTH: 20px; HEIGHT: 20px
}
PRE {
    BORDER-RIGHT: #ccc 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #ccc 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #ccc 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #ccc 1px solid; BACKGROUND-COLOR: #f8f8f0
}
</STYLE>
<body>
<FIELDSET id=Demo4><LEGEND>样例- 拖拽页面元素</LEGEND>
      <DIV>
        <DIV class=DragContainer id=DragContainer4 overclass="OverDragContainer">
            <DIV class=DragBox id=Item1 overclass="OverDragBox" dragclass="DragDragBox">Item #1</DIV>
            <DIV class=DragBox id=Item2 overclass="OverDragBox" dragclass="DragDragBox">Item #2</DIV>
            <DIV class=DragBox id=Item3 overclass="OverDragBox" dragclass="DragDragBox">Item #3</DIV>
            <DIV class=DragBox id=Item4 overclass="OverDragBox" dragclass="DragDragBox">Item #4</DIV>
        </DIV>
       
        <DIV class=DragContainer id=DragContainer5 overclass="OverDragContainer">
            <DIV class=DragBox id=Item5 overclass="OverDragBox" dragclass="DragDragBox">Item #5</DIV>
            <DIV class=DragBox id=Item6 overclass="OverDragBox" dragclass="DragDragBox">Item #6</DIV>
            <DIV class=DragBox id=Item7 overclass="OverDragBox" dragclass="DragDragBox">Item #7</DIV>
            <DIV class=DragBox id=Item8 overclass="OverDragBox" dragclass="DragDragBox">Item #8</DIV>
        </DIV>
       
        <DIV class=DragContainer id=DragContainer6 overclass="OverDragContainer">
            <DIV class=DragBox id=Item9 overclass="OverDragBox" dragclass="DragDragBox">Item #9</DIV>
            <DIV class=DragBox id=Item10 overclass="OverDragBox" dragclass="DragDragBox">Item #10</DIV>
            <DIV class=DragBox id=Item11 overclass="OverDragBox" dragclass="DragDragBox">Item #11</DIV>
            <DIV class=DragBox id=Item12 overclass="OverDragBox" dragclass="DragDragBox">Item #12</DIV>
        </DIV>
    </DIV>
</FIELDSET>

</body>
</html>


Javascript部份:
var Demos       = [];
var nDemos      = 8;

var mouseOffset = null;
var iMouseDown  = false;
var lMouseState = false;
var dragObject  = null;

// Demo 0 variables
var DragDrops   = [];
var curTarget   = null;
var lastTarget  = null;
var dragHelper  = null;
var tempDiv     = null;
var rootParent  = null;
var rootSibling = null;
var nImg        = new Image();

nImg.src        = 'images/drag_drop_poof.gif';

// Demo1 variables
var D1Target    = null;

Number.prototype.NaN0=function(){return isNaN(this)?0:this;}

function CreateDragContainer(){
    /*
    Create a new "Container Instance" so that items from one "Set" can not
    be dragged into items from another "Set"
    */

    var cDrag        = DragDrops.length;
    DragDrops[cDrag] = [];

    /*
    Each item passed to this function should be a "container".  Store each
    of these items in our current container
    */

    for(var i=0; i<arguments.length; i++){
        var cObj = arguments[i];
        DragDrops[cDrag].push(cObj);
        cObj.setAttribute('DropObj', cDrag);

        /*
        Every top level item in these containers should be draggable.  Do this
        by setting the DragObj attribute on each item and then later checking
        this attribute in the mouseMove function
        */
        for(var j=0; j<cObj.childNodes.length; j++){

            // Firefox puts in lots of #text nodes...skip these
            if(cObj.childNodes[j].nodeName=='#text') continue;

            cObj.childNodes[j].setAttribute('DragObj', cDrag);
        }
    }
}

function getPosition(e){
    var left = 0;
    var top  = 0;
    while (e.offsetParent){
        left += e.offsetLeft + (e.currentStyle?(parseInt(e.currentStyle.borderLeftWidth)).NaN0():0);
        top  += e.offsetTop  + (e.currentStyle?(parseInt(e.currentStyle.borderTopWidth)).NaN0():0);
        e     = e.offsetParent;
    }

    left += e.offsetLeft + (e.currentStyle?(parseInt(e.currentStyle.borderLeftWidth)).NaN0():0);
    top  += e.offsetTop  + (e.currentStyle?(parseInt(e.currentStyle.borderTopWidth)).NaN0():0);

    return {x:left, y:top};

}

function mouseCoords(ev){
    if(ev.pageX || ev.pageY){
        return {x:ev.pageX, y:ev.pageY};
    }
    return {
        x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
        y:ev.clientY + document.body.scrollTop  - document.body.clientTop
    };
}

function writeHistory(object, message){
    if(!object || !object.parentNode || !object.parentNode.getAttribute) return;
    var historyDiv = object.parentNode.getAttribute('history');
    if(historyDiv){
        historyDiv = document.getElementById(historyDiv);
        historyDiv.appendChild(document.createTextNode(object.id+': '+message));
        historyDiv.appendChild(document.createElement('BR'));

        historyDiv.scrollTop += 50;
    }
}

function getMouseOffset(target, ev){
    ev = ev || window.event;

    var docPos    = getPosition(target);
    var mousePos  = mouseCoords(ev);
    return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
}

function mouseMove(ev){
    ev         = ev || window.event;

    var target   = ev.target || ev.srcElement;
    var mousePos = mouseCoords(ev);

    if(Demos[0] || Demos[4]){
        // mouseOut event - fires if the item the mouse is on has changed
        if(lastTarget && (target!==lastTarget)){
            writeHistory(lastTarget, 'Mouse Out Fired');

            // reset the classname for the target element
            var origClass = lastTarget.getAttribute('origClass');
            if(origClass) lastTarget.className = origClass;
        }

        var dragObj = target.getAttribute('DragObj');

         // if the mouse was moved over an element that is draggable
        if(dragObj!=null){

            // mouseOver event - Change the item's class if necessary
            if(target!=lastTarget){
                writeHistory(target, 'Mouse Over Fired');

                var oClass = target.getAttribute('overClass');
                if(oClass){
                    target.setAttribute('origClass', target.className);
                    target.className = oClass;
                }
            }

            // if the user is just starting to drag the element
            if(iMouseDown && !lMouseState){
                writeHistory(target, 'Start Dragging');
                // mouseDown target
                curTarget     = target;

                // Record the mouse x and y offset for the element
                rootParent    = curTarget.parentNode;
                rootSibling   = curTarget.nextSibling;

                mouseOffset   = getMouseOffset(target, ev);

                // We remove anything that is in our dragHelper DIV so we can put a new item in it.
                for(var i=0; i<dragHelper.childNodes.length; i++) {
                    dragHelper.removeChild(dragHelper.childNodes[i]);
                }

                // Make a copy of the current item and put it in our drag helper.
                dragHelper.appendChild(curTarget.cloneNode(true));
                dragHelper.style.display = 'block';

                // set the class on our helper DIV if necessary
                var dragClass = curTarget.getAttribute('dragClass');
                if(dragClass){
                    dragHelper.firstChild.className = dragClass;
                }

                // disable dragging from our helper DIV (it's already being dragged)
                dragHelper.firstChild.removeAttribute('DragObj');

                var dragConts = DragDrops[dragObj];

                curTarget.setAttribute('startWidth',  parseInt(curTarget.offsetWidth));
                curTarget.setAttribute('startHeight', parseInt(curTarget.offsetHeight));
                curTarget.style.display  = 'none';

                // loop through each possible drop container
                for(var i=0; i<dragConts.length; i++){
                    with(dragConts[i]){
                        var pos = getPosition(dragConts[i]);
                        setAttribute('startWidth',  parseInt(offsetWidth));
                        setAttribute('startHeight', parseInt(offsetHeight));
                        setAttribute('startLeft',   pos.x);
                        setAttribute('startTop',    pos.y);
                    }

                    // loop through each child element of each container
                    for(var j=0; j<dragConts[i].childNodes.length; j++){
                        with(dragConts[i].childNodes[j]){
                            if((nodeName=='#text') || (dragConts[i].childNodes[j]==curTarget)) continue;

                            var pos = getPosition(dragConts[i].childNodes[j]);

                            // save the width, height and position of each element
                            setAttribute('startWidth',  parseInt(offsetWidth));
                            setAttribute('startHeight', parseInt(offsetHeight));
                            setAttribute('startLeft',   pos.x);
                            setAttribute('startTop',    pos.y);
                        }
                    }
                }
            }
        }

        // If we get in here we are dragging something
        if(curTarget){
            // move our helper div to wherever the mouse is (adjusted by mouseOffset)
            dragHelper.style.top  = mousePos.y - mouseOffset.y;
            dragHelper.style.left = mousePos.x - mouseOffset.x;

            var dragConts  = DragDrops[curTarget.getAttribute('DragObj')];
            var activeCont = null;

            var xPos = mousePos.x - mouseOffset.x + (parseInt(curTarget.getAttribute('startWidth')) /2);
            var yPos = mousePos.y - mouseOffset.y + (parseInt(curTarget.getAttribute('startHeight'))/2);

            // check each drop container to see if our target object is "inside" the container
            for(var i=0; i<dragConts.length; i++){
                with(dragConts[i]){
                    if((parseInt(getAttribute('startLeft'))                                           < xPos) &&
                        (parseInt(getAttribute('startTop'))                                            < yPos) &&
                        ((parseInt(getAttribute('startLeft')) + parseInt(getAttribute('startWidth')))  > xPos) &&
                        ((parseInt(getAttribute('startTop'))  + parseInt(getAttribute('startHeight'))) > yPos)){

                            activeCont = dragConts[i];

                            // exit the for loop
                            break;
                    }
                }
            }

            // Our target object is in one of our containers.  Check to see where our div belongs
            if(activeCont){
                if(activeCont!=curTarget.parentNode){
                    writeHistory(curTarget, 'Moved into '+activeCont.id);
                }

                // beforeNode will hold the first node AFTER where our div belongs
                var beforeNode = null;

                // loop through each child node (skipping text nodes).
                for(var i=activeCont.childNodes.length-1; i>=0; i--){
                    with(activeCont.childNodes[i]){
                        if(nodeName=='#text') continue;

                        // if the current item is "After" the item being dragged
                        if(curTarget != activeCont.childNodes[i]                                                  &&
                            ((parseInt(getAttribute('startLeft')) + parseInt(getAttribute('startWidth')))  > xPos) &&
                            ((parseInt(getAttribute('startTop'))  + parseInt(getAttribute('startHeight'))) > yPos)){
                                beforeNode = activeCont.childNodes[i];
                        }
                    }
                }

                // the item being dragged belongs before another item
                if(beforeNode){
                    if(beforeNode!=curTarget.nextSibling){
                        writeHistory(curTarget, 'Inserted Before '+beforeNode.id);

                        activeCont.insertBefore(curTarget, beforeNode);
                    }

                // the item being dragged belongs at the end of the current container
                } else {
                    if((curTarget.nextSibling) || (curTarget.parentNode!=activeCont)){
                        writeHistory(curTarget, 'Inserted at end of '+activeCont.id);

                        activeCont.appendChild(curTarget);
                    }
                }

                // the timeout is here because the container doesn't "immediately" resize
                setTimeout(function(){
                var contPos = getPosition(activeCont);
                activeCont.setAttribute('startWidth',  parseInt(activeCont.offsetWidth));
                activeCont.setAttribute('startHeight', parseInt(activeCont.offsetHeight));
                activeCont.setAttribute('startLeft',   contPos.x);
                activeCont.setAttribute('startTop',    contPos.y);}, 5);

                // make our drag item visible
                if(curTarget.style.display!=''){
                    writeHistory(curTarget, 'Made Visible');
                    curTarget.style.display    = '';
                    curTarget.style.visibility = 'hidden';
                }
            } else {

                // our drag item is not in a container, so hide it.
                if(curTarget.style.display!='none'){
                    writeHistory(curTarget, 'Hidden');
                    curTarget.style.display  = 'none';
                }
            }
        }

        // track the current mouse state so we can compare against it next time
        lMouseState = iMouseDown;

        // mouseMove target
        lastTarget  = target;
    }
    if(dragObject){
        dragObject.style.position = 'absolute';
        dragObject.style.top      = mousePos.y - mouseOffset.y;
        dragObject.style.left     = mousePos.x - mouseOffset.x;
    }

    // track the current mouse state so we can compare against it next time
    lMouseState = iMouseDown;

    // this prevents items on the page from being highlighted while dragging
    if(curTarget || dragObject) return false;
}

function mouseUp(ev){

    if(Demos[0] || Demos[4]){
        if(curTarget){
            writeHistory(curTarget, 'Mouse Up Fired');

            dragHelper.style.display = 'none';
            if(curTarget.style.display == 'none'){
                if(rootSibling){
                    rootParent.insertBefore(curTarget, rootSibling);
                } else {
                    rootParent.appendChild(curTarget);
                }
            }
            curTarget.style.display    = '';
            curTarget.style.visibility = 'visible';
        }
        curTarget  = null;
    }
    dragObject = null;

    iMouseDown = false;
}

function mouseDown(ev){
    ev         = ev || window.event;
    var target = ev.target || ev.srcElement;
    iMouseDown = true;
    if(Demos[0] || Demos[4]){
        if(lastTarget){
            writeHistory(lastTarget, 'Mouse Down Fired');
        }
    }
    if(target.onmousedown || target.getAttribute('DragObj')){
        return false;
    }
}

function makeDraggable(item){
    if(!item) return;
    item.onmousedown = function(ev){
        dragObject  = this;
        mouseOffset = getMouseOffset(this, ev);
        return false;
    }
}

function makeClickable(item){
    if(!item) return;
    item.onmousedown = function(ev){
        document.getElementById('ClickImage').value = this.name;
    }
}

function addDropTarget(item, target){
    item.setAttribute('droptarget', target);
}

document.onmousemove = mouseMove;
document.onmousedown = mouseDown;
document.onmouseup   = mouseUp;

window.onload = function(){
    for(var i=0; i<nDemos; i++){
        Demos[i] = document.getElementById('Demo'+i);
    }
    if(Demos[4]){
        CreateDragContainer(document.getElementById('DragContainer4'), document.getElementById('DragContainer5'), document.getElementById('DragContainer6'));
    }
    if(Demos[0] || Demos[4]){
        // Create our helper object that will show the item while dragging
        dragHelper = document.createElement('DIV');
        dragHelper.style.cssText = 'position:absolute;display:none;';

        document.body.appendChild(dragHelper);
    }
}

meiking   2008-04-10 01:54:29 评论:0   阅读:25   引用:0

发表评论>>

署名发表(评论可管理,不必输入下面的姓名)

姓名:

主题:

内容: 最少15个,最长1000个字符

验证码: (如不清楚,请刷新)

Copyright@2006 powered by YuLog