js拖拽(二)仿iGoogle自定义首页模块拖拽

来源:互联网 发布:怎么下架淘宝宝贝 编辑:程序博客网 时间:2024/06/06 00:53

作者:JayChow 
出处:http://ljchow.cnblogs.com 

代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head>    <title></title>    <script type="text/javascript">        var Common = {            getEvent: function() {//ie/ff                 if (document.all) {                    return window.event;                }                func = getEvent.caller;                while (func != null) {                    var arg0 = func.arguments[0];                    if (arg0) {                        if ((arg0.constructor == Event || arg0.constructor == MouseEvent) || (typeof (arg0) == "object" && arg0.preventDefault && arg0.stopPropagation)) {                            return arg0;                        }                    }                    func = func.caller;                }                return null;            },            getMousePos: function(ev) {                if (!ev) {                    ev = this.getEvent();                }                if (ev.pageX || ev.pageY) {                    return {                        x: ev.pageX,                        y: ev.pageY                    };                }                if (document.documentElement && document.documentElement.scrollTop) {                    return {                        x: ev.clientX + document.documentElement.scrollLeft - document.documentElement.clientLeft,                        y: ev.clientY + document.documentElement.scrollTop - document.documentElement.clientTop                    };                }                else if (document.body) {                    return {                        x: ev.clientX + document.body.scrollLeft - document.body.clientLeft,                        y: ev.clientY + document.body.scrollTop - document.body.clientTop                    };                }            },            getElementPos: function(el) {                el = this.getItself(el);                var _x = 0, _y = 0;                do {                    _x += el.offsetLeft;                    _y += el.offsetTop;                } while (el = el.offsetParent);                return { x: _x, y: _y };            },            getItself: function(id) {                return "string" == typeof id ? document.getElementById(id) : id;            },            getViewportSize: { w: (window.innerWidth) ? window.innerWidth : (document.documentElement && document.documentElement.clientWidth) ? document.documentElement.clientWidth : (document.body?document.body.offsetWidth:0), h: (window.innerHeight) ? window.innerHeight : (document.documentElement && document.documentElement.clientHeight) ? document.documentElement.clientHeight : (document.body ? document.body.offsetHeight : 0) },            isIE: document.all ? true : false,            setOuterHtml: function(obj, html) {                var Objrange = document.createRange();                obj.innerHTML = html;                Objrange.selectNodeContents(obj);                var frag = Objrange.extractContents();                obj.parentNode.insertBefore(frag, obj);                obj.parentNode.removeChild(obj);            },            firstChild: function(parentObj, tagName) {                if (Common.isIE) {                    return parentObj.firstChild;                }                else {                    var arr = parentObj.getElementsByTagName(tagName);                    return arr[0];                }            },            lastChild: function(parentObj, tagName) {                if (Common.isIE) {                    return parentObj.lastChild;                }                else {                    var arr = parentObj.getElementsByTagName(tagName);                    return arr[arr.length - 1];                }            },            setCookie: function(name, value) {                document.cookie = name + "=" + value;            },            getCookie: function(name) {                var strCookie = document.cookie;                var arrCookie = strCookie.split("; ");                for (var i = 0; i < arrCookie.length; i++) {                    var arr = arrCookie[i].split("=");                    if (!arr[1]) {                        return "";                    }                    if (arr[0] == name) {                        return arr[1];                    }                }                return "";            },            delCookie: function(name) {                var exp = new Date();                exp.setTime(exp.getTime() - 1);                var cval = this.getCookie(name);                if (cval != null) document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();            }        }                ///------------------------------------------------------------------------------------------------------         var Class = {            create: function() {                return function() { this.init.apply(this, arguments); }            }        }        var Drag = Class.create();        Drag.prototype = {            init: function(titleBar, dragDiv, Options) {                //设置点击是否透明,默认透明60%                 titleBar = Common.getItself(titleBar);                dragDiv = Common.getItself(dragDiv);                this.dragArea = { maxLeft: -9999, maxRight: 9999, maxTop: -9999, maxBottom: 9999 };                if (Options) {                    this.opacity = Options.opacity ? (isNaN(parseInt(Options.opacity)) ? 100 : parseInt(Options.opacity)) : 100;                    if (Options.area) {                        if (Options.area.left && !isNaN(parseInt(Options.area.left))) { this.dragArea.maxLeft = Options.area.left };                        if (Options.area.right && !isNaN(parseInt(Options.area.right))) { this.dragArea.maxRight = Options.area.right };                        if (Options.area.top && !isNaN(parseInt(Options.area.top))) { this.dragArea.maxTop = Options.area.top };                        if (Options.area.bottom && !isNaN(parseInt(Options.area.bottom))) { this.dragArea.maxBottom = Options.area.bottom };                    }                }                else {                    this.opacity = 60;                }                this.originDragDiv = null;                this.tmpX = 0;                this.tmpY = 0;                this.moveable = false;                this.dragArray = [];                var dragObj = this;                var dragTbl = document.getElementById("dragTable");                titleBar.onmousedown = function(e) {                    var ev = e || window.event || Common.getEvent();                    //只允许通过鼠标左键进行拖拽,IE鼠标左键为1 FireFox为0                     if (Common.isIE && ev.button == 1 || !Common.isIE && ev.button == ground-color: #f5f5f5; color: #000000;">0) {                    }                    else {                        return false;                    }                    //处理特殊情况:在最上/下面MOVE时不碰到现有DIV的情况下,又回到起始拖拽的列最上/下方                     var tmpColId;                    for (c = 0; c < dragTbl.rows[0].cells.length; c++) {                        for (k = 0; k < dragTbl.rows[0].cells[c].getElementsByTagName("DIV").length; k++) {                            if (dragDiv.id == dragTbl.rows[0].cells[c].getElementsByTagName("DIV")[k].id) {                                tmpColId = c;                                break;                            }                        }                    }                    var tmpPosFirstChild = Common.getElementPos(Common.firstChild(dragTbl.rows[0].cells[tmpColId], "DIV"));                    var tmpPosLastChild = Common.getElementPos(Common.lastChild(dragTbl.rows[0].cells[tmpColId], "DIV"));                    var tmpObj = { colId: tmpColId, firstChildUp: tmpPosFirstChild.y, lastChildDown: tmpPosLastChild.y + Common.lastChild(dragTbl.rows[0].cells[tmpColId], "DIV").offsetHeight };                    //保存当前可拖拽各容器的所在位置                     dragObj.dragArray = dragObj.RegDragsPos();                    //插入虚线框                     var dashedElement = document.createElement("div");                    dashedElement.style.cssText = dragDiv.style.cssText;                    dashedElement.style.border = " dashed 2px #aaa ";                    dashedElement.style.marginBottom = "6px";                    dashedElement.style.width = dragDiv.offsetWidth - 2 * parseInt(dashedElement.style.borderWidth) + "px"; //减去boderWidth使虚线框大小保持与dragDiv一致                     dashedElement.style.height = dragDiv.offsetHeight - 2 * parseInt(dashedElement.style.borderWidth) + "px"; //加上px 保证FF正确                                         dashedElement.style.position = "relative";                    if (dragDiv.nextSibling) {                        dragDiv.parentNode.insertBefore(dashedElement, dragDiv.nextSibling);                    }                    else {                        dragDiv.parentNode.appendChild(dashedElement);                    }                    //拖动时变为absolute                     dragDiv.style.width = dragDiv.offsetWidth + "px";                    dragDiv.style.position = "absolute";                    dragObj.moveable = true;                    dragDiv.style.zIndex = dragObj.GetZindex() + 1;                    var downPos = Common.getMousePos(ev);                    dragObj.tmpX = downPos.x - dragDiv.offsetLeft;                    dragObj.tmpY = downPos.y - dragDiv.offsetTop;                    if (Common.isIE) {                        dragDiv.setCapture();                    } else {                        window.captureEvents(Event.mousemove);                    }                    dragObj.SetOpacity(dragDiv, dragObj.opacity);                    //FireFox 去除容器内拖拽图片问题                     if (ev.preventDefault) {                        ev.preventDefault();                        ev.stopPropagation();                    }                    document.onmousemove = function(e) {                        if (dragObj.moveable) {                            var ev = e || window.event ||t;background-color: #f5f5f5; color: #000000;"> Common.getEvent();                            //IE 去除容器内拖拽图片问题                             if (document.all) //IE                            {                                ev.returnValue = false;                            }                            var movePos = Common.getMousePos(ev);                            dragDiv.style.left = Math.max(Math.min(movePos.x - dragObj.tmpX, dragObj.dragArea.maxRight), dragObj.dragArea.maxLeft) + "px";                            dragDiv.style.top = Math.max(Math.min(movePos.y - dragObj.tmpY, dragObj.dragArea.maxBottom), dragObj.dragArea.maxTop) + "px";                            var targetDiv = null;                            for (var k = 0; k < dragObj.dragArray.length; k++) {                                if (dragDiv == dragObj.dragArray[i]) {                                    continue;                                }                                if (movePos.x > dragObj.dragArray[k].PosLeft && movePos.x < dragObj.dragArray[k].PosLeft + dragObj.dragArray[k].PosWidth                                    && movePos.y > dragObj.dragArray[k].PosTop && movePos.y < dragObj.dragArray[k].PosTop + dragObj.dragArray[k].PosHeight                                ) {                                    targetDiv = document.getElementById(dragObj.dragArray[k].DragId);                                    if (movePos.y < dragObj.dragArray[k].PosTop + dragObj.dragArray[k].PosHeight / 2) {                                        //往上移                                        dashedElement.style.width = targetDiv.offsetWidth - 2 * parseInt(dashedElement.style.borderWidth) + "px";                                        targetDiv.parentNode.insertBefore(dashedElement, targetDiv);                                    }                                    else {                                        //往下移                                        dashedElement.style.width = targetDiv.offsetWidth - 2 * parseInt(dashedElement.style.borderWidth) + "px";                                        if (targetDiv.nextSibling) {                                            targetDiv.parentNode.insertBefore(dashedElement, targetDiv.nextSibling);                                        }                                        else {                                            targetDiv.parentNode.appendChild(dashedElement);                                        }                                    }                                }                            }                                                        for (j = 0; j < dragTbl.rows[0].cells.length; j++) {                                var startLeft = Common.getElementPos(dragTbl.rows[0].cells[j]).x;                                if (movePos.x > startLeft && movePos.x < startLeft + dragTbl.rows[0].cells[j].offsetWidth) {                                    ///列无DIV                                    if (dragTbl.rows[0].cells[j].getElementsByTagName("div").length == 0) {                                        dashedElement.style.width = dragTbl.rows[0].cells[j].offsetWidth - 2 * parseInt(dashedElement.style.borderWidth) + "px";                                        dragTbl.rows[0].cells[j].appendChild(dashedElement);                                    }                                    else {                                        var posFirstChild = Common.getElementPos(Common.firstChild(dragTbl.rows[0].cells[j], "DIV"));                                        var posLastChild = Common.getElementPos(Common.lastChild(dragTbl.rows[0].cells[j], "DIV"));                                        //处理特殊情况:在最上/下面MOVE时不碰到现有DIV的情况下,又回到起始拖拽的列最上/下方                                        var tmpUp, tmpDown;                                        if (tmpObj.colId == j) {                                            tmpUp = tmpObj.firstChildUp;                                            tmpDown = tmpObj.lastChildDown;                                        }                                        else {                                            tmpUp = posFirstChild.y;                                            tmpDown = posLastChild.y + Common.lastChild(dragTbl.rows[0].cells[j], "DIV").offsetHeight;                                        }                                        if (movePos.y < tmpUp) {///从最上面插入虚线框                                            dashedElement.style.width = Common.firstChild(dragTbl.rows[0].cells[j], "DIV").offsetWidth - 2 * parseInt(dashedElement.style.borderWidth) + "px";                                            dragTbl.rows[0].cells[j].insertBefore(dashedElement, Common.firstChild(dragTbl.rows[0].cells[j], "DIV"));                                        }                                        else if (movePos.y > tmpDown) {///从最下面插入虚线框                                            dashedElement.style.width = Common.lastChild(dragTbl.rows[0].cells[j], "DIV").offsetWidth - 2 * parseInt(dashedElement.style.borderWidth) + "px";                                            dragTbl.rows[0].cells[j].appendChild(dashedElement);                                        }                                    }                                }                            }                        }                    };                    document.onmouseup = function() {                        if (dragObj.moveable) {                            if (Common.isIE) {                                dragDiv.releaseCapture();                            }                            else {                                window.releaseEvents(dragDiv.mousemove);                            }                            dragObj.SetOpacity(dragDiv, 100);                            dragObj.moveable = false;                            dragObj.tmpX = 0;                            dragObj.tmpY = 0;                            //务必写在此IF内                            dragDiv.style.left = "";                            dragDiv.style.top = "";                            dragDiv.style.width = "";                            dragDiv.style.position = "";                              dashedElement.parentNode.insertBefore(dragDiv, dashedElement);                            dashedElement.parentNode.removeChild(dashedElement);                        }                    };                }            },            SetOpacity: function(dragDiv, n) {                if (Common.isIE) {                    dragDiv.filters.alpha.opacity = n;                }                else {                    dragDiv.style.opacity = n / 100;                }            },            GetZindex: function() {                var maxZindex = 0;                var divs = document.getElementsByTagName("div");                for (z = 0; z < divs.length; z++) {                    maxZindex = Math.max(maxZindex, divs[z].style.zIndex);                }                return maxZindex;            },            RegDragsPos: function() {                var arrDragDivs = new Array();                var dragTbl = document.getElementById("dragTable");                var tmpDiv, tmpPos;                for (i = 0; i < dragTbl.getElementsByTagName("div").length; i++) {                    tmpDiv = dragTbl.getElementsByTagName("div")[i];                    if (tmpDiv.className = "dragDiv") {                        tmpPos = Common.getElementPos(tmpDiv);                        arrDragDivs.push({ DragId: tmpDiv.id, PosLeft: tmpPos.x, PosTop: tmpPos.y, PosWidth: tmpDiv.offsetWidth, PosHeight: tmpDiv.offsetHeight });                    }                }                return arrDragDivs;            }        }        window.onload = function() {            var dragTbl = document.getElementById("dragTable");            if (Common.getCookie("configArr")) {                var configArr = eval("(" + Common.getCookie("configArr") + ")");                for (i = 0; i < dragTbl.rows[0].cells.length; i++) {                    for (j = 0; j < configArr[i].length; j++) {                        dragTbl.rows[0].cells[i].appendChild(document.getElementById(configArr[i][j]));                    }                }            }            new Drag("titleBar1", "dragDiv1");            new Drag("titleBar2", "dragDiv2");            new Drag("titleBar3", "dragDiv3");            new Drag("titleBar4", "dragDiv4");            new Drag("titleBar5", "dragDiv5");        }        window.onunload = function() {            var dragTbl = document.getElementById("dragTable");            var configArr = "";            for (i = 0; i < dragTbl.rows[0].cells.length; i++) {                var tmpStr = "";                for (j = 0; j < dragTbl.rows[0].cells[i].getElementsByTagName("DIV").length; j++) {                    tmpStr += (tmpStr == "" ? "" : ",") + "'" + dragTbl.rows[0].cells[i].getElementsByTagName("DIV")[j].id + "'";                }                configArr += (configArr == "" ? "" : ",") + "[" + tmpStr + "]";            }            //format like: [['dragDiv3','dragDiv5'],['dragDiv4','dragDiv1'],['dragDiv2']]            Common.setCookie("configArr", "[" + configArr + "]");                    }    </script>    <style type="text/css">    .spanDiv{    position:relative;    width:5px;    height:5px;    }    .dragDiv,.nodragDiv{    position:relative;    filter:alpha(opacity=100);    opacity:1;    margin-bottom:6px;    background-color:#FFFFFF;    }    </style></head><body > <script type="text/javascript"></script>       <table id="dragTable" cellpadding="3"  style=" border:solid 0px green;width:98%;">        <tr>            <td valign="top" style="width:30%">                <div class="dragDiv" id="dragDiv1" >                    <table cellpadding="0" cellspacing="0" border="1" style="width:100%;border-collapse:collapse; border-color:Blue">                        <tr id="titleBar1"  style="height:22px; text-align:left; background-color:#547BC9;color:White; padding:3px;cursor:move;">                            <th align="left" unselectable="on" >Title1</th>                        </tr>                        <tr style="height:130px;padding:3px;" align="left" valign="top" >                            <td unselectable="on">Content1...</td>                         </tr>                    </table>                </div>                               <div class="dragDiv" id="dragDiv2">                    <table cellpadding="0" cellspacing="0" border="1" style="width:100%;border-collapse:collapse; border-color:Blue">                        <tr id="titleBar2" style="height:22px; text-align:left; background-color:#547BC9;color:White; padding:3px;cursor:move;">                            <th align="left" unselectable="on" >Title2</th>                        </tr>                        <tr style="height:130px;padding:3px;" align="left" valign="top" >                            <td unselectable="on">Content2...</td>                         </tr>                    </table>                </div>            </td>            <td valign="top" style="width:50%">                <div class="dragDiv" id="dragDiv3">                    <table cellpadding="0" cellspacing="0" border="1" style="width:100%;border-collapse:collapse; border-color:Blue">                        <tr id="titleBar3" style="height:22px; text-align:left; background-color:#547BC9;color:White; padding:3px;cursor:move;">                            <th align="left" unselectable="on" >Title3</th>                        </tr>                        <tr style="height:230px;padding:3px;" align="left" valign="top" >                            <td unselectable="on">Content3...</td>                         </tr>                    </table>                </div>                            </td>            <td valign="top" style="width:20%">                <div class="dragDiv" id="dragDiv4">                    <table cellpadding="0" cellspacing="0" border="1" style="width:100%;border-collapse:collapse; border-color:Blue">                        <tr id="titleBar4" style="height:22px; text-align:left; background-color:#547BC9;color:White; padding:3px;cursor:move;">                            <th align="left" unselectable="on" >Title4</th>                        </tr>                        <tr style="height:130px;padding:3px;" align="left" valign="top" >                            <td unselectable="on">Content4...</td>                         </tr>                    </table>                </div>                <div class="dragDiv" id="dragDiv5">                    <table cellpadding="0" cellspacing="0" border="1" style="width:100%;border-collapse:collapse; border-color:Blue">                        <tr id="titleBar5" style="height:22px; text-align:left; background-color:#547BC9;color:White; padding:3px;cursor:move;">                            <th align="left" unselectable="on" >Title5</th>                        </tr>                        <tr style="height:130px;padding:3px;" align="left" valign="top" >                            <td unselectable="on">Content5...</td>                         </tr>                    </table>                </div>            </td>        </tr>        </table></body></html>

1. 准备

1.1 由于模块拖拽中使用虚线框,所以去除(一)中拖拽的保持原有DIV的功能(即keepOrigin);
1.2 在新建Drag对象时如未设置拖拽时透明值,默认改为60%的透明度;

1.3 将拖拽范围上下左右默认设置为9999,因为模块拖拽超过当前可视窗口是必要的。

1.4 在(一)中有个BUG,即用IE第一次打开页面报缺少对象的错,如要重现,右键文件选择IE打开,刷新后或者将文件拖到已有IE浏览器中无法重现。原因Common.getViewportSize中有document.body.offsetWidth,IE中第一次打开,当解析到这句时,document.body不存在,所以取offsetWidth时错误。所以要么把这段放到body标签中,要么进行对document.body的判断。

1.5 HTML结构:这里使用的是Table,在TD中存放要拖拽的DIV。当然也可以全部用DIV布局。但是拖拽的DIV的postion要设为relative,因为他是在文档流中的,absolute则是脱离文档流。

 

2. 思路及注意点

2.1 在mouseDown时,插入虚线框DIV,这里要注意设置虚线框的position为relative,插入到当前拖拽DIV所处列的文档流中,同时把当前拖拽DIV的position改为absolute,使脱离文档流来进行拖拽。虚线框DIV的宽度要注意减去2倍的boderWidth,否则虚线框将撑大当前列,造成文档布局移位。同时,保证插入虚线框DIV的code要在赋当前拖拽DIV的ZIndex值前面,以保证当前拖拽DIV的ZIndex最大。

2.2 在mouseUp时,插入当前拖拽DIV至虚线框前,将当前拖拽DIV的position、left、top、width清空,进入文档流。然后删除虚线框。

2.3 模块自定义拖拽的核心操作即在mouseMove时。
2.3.1 首先是虚线框的高度宽度处理,我的处理是高度保持不变,宽度取所移动到当前列的宽度。
2.3.2 然后核心问题是:什么时候让虚线框移动到什么位置。

我的处理是:拿当前拖拽中的鼠标位置与页面可拖拽的各DIV的绝对位置进行比较。所以在mouseDown时还要记住当前页面可拖拽DIV的绝对位置和宽度高度(RegDragsPos方法中),存入数组。
当拖拽中鼠标进入某DIV区域内,如在该DIV上半部,则虚线框插到该DIV的上方,如在下半部则插在下方。
当拖拽中鼠标并未触及某具体DIV区域内,在外部游离时,则首先判断处于那一列范围内,然后如果该列没有可拖拽DIV,则虚线框直接插入该列;若该列有DIV,则判断鼠标位置处于该列第一个DIV上方,则往上插,处于该列最下面DIV下方,则往下插。至此所有可能情况均处理。
有一特殊情况,譬如,当前拖拽DIV在最上方游离,鼠标不碰及任何DIV,从第一列开始,移动到第二第三列虚线框插入均正常,但是回到第一列时发现无法插入。因为此时当前拖拽的DIV仍然作为第一列的第一个DIV,在判断是否位于该列第一个DIV上方时不符合条件无法执行虚线框插入的操作。所以在mouseDown时临时记下该列第一个DIV的top和最后一个DIV 下沿绝对位置,以此比较。

对于什么时候让虚线框移动到什么位置,IGoogle以前版本的处理是:找到取距离当前鼠标位置这点最近的可拖拽DIV(取最短的两点间距离),然后让虚线框插入该DIV处。现在版本不清楚怎么做的。

 

3.拖拽之后保存当前模块布局,使刷新页面仍保持自定义的模块布局。
其实是在window.onunload中用cookie记下当前布局状态,如: [['dragDiv3','dragDiv5'],['dragDiv4','dragDiv1'],['dragDiv2']] 。window.onload中去布局。实际应用中可以将此插入后台数据库进行保存。

 





0 0
原创粉丝点击