js应用-实现博客个性主页布局拖拽功能

Jquery的Interface elements for jQuery里面的拖拽布局存在一些bug,效率也比较低,GoogleUI google_drag.js有些乱,不是很容易理解,Discuz!NT Space代码满天飞,所以自己参考GoogleUI的思想,简化和优化了一些操作代码,实现了博客系统基本的拖拽布局的效果,暂时未考虑其他浏览器的兼容性问题。下一步准备改造成Jquery的插件形式,并增加一些渐隐渐现和动画效果,并逐步实现一些ajax的添加删除操作,嵌入基于JQuery的音乐播放器,图片浏览器,文本编辑器

预览体验:
 
html代码:
下面的可拖拽模块的mid为其在数据库中的id号;
<div style="display:inline" mid="|"><div></div></div>
每td列最后都有一个,并隐藏起来,用来可以推拽元素到此隐藏元素的前面,或者某td列本来没有元素,
也可以拖拽到此列上面:

 1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 2<html xmlns="http://www.w3.org/1999/xhtml">
 3<head>
 4<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
 5<title>博客推拽布局示例</title>
 6<link href="main.css" rel="stylesheet" type="text/css" />
 7<script src="drag.js" language="javascript"></script>
 8</head>
 9
10<body>
11<div id="modules"> 
12    <table id="main" cellspacing="10" border="0" width="98%" align="center"> 
13        <tr> 
14            <td id="c1">
15                <div class="module" mid="1">
16                    <div class="title">title1</div>
17                    <div class="content">content1</div>
18                </div>                
19                <div class="module" mid="4">
20                    <div class="title">title4</div>
21                    <div class="content">content4</div>
22                </div>
23                <div style="display:inline" mid="|"><div></div></div>
24            </td> 
25            <td id="c2" > 
26                 <div class="module" mid="2">
27                    <div class="title">title2</div>
28                    <div class="content">content2</div>
29                </div>
30                <div style="display:inline" mid="|"><div></div></div>
31            </td> 
32            <td id="c3" > 
33                 <div class="module" mid="3">
34                    <div class="title">title3</div>
35                    <div class="content">content3</div>
36                </div>
37                <div style="display:inline" mid="|"><div></div></div>
38            </td> 
39        </tr> 
40    </table>
41    <div id="ghost"></div> 
42</div> 
43布局顺序为:<span id="order" />
44<script>
45    //实例化一个dragLayout对象
46    var dragObj = new guozili.dragLayout({
47        targetId: "main",
48        //dragArray为拖拽完后新的dragModule对象
49        onEnd: function(dragArray) {        
50            var order = "";
51            for(var i in dragArray)        
52            {
53                order += dragArray[i].ele.getAttribute("mid"+ " ";
54            }

55            
56            getElementById("order").innerText = order;
57            //或者进行ajax提交
58        }
        
59        
60    }
);
61    
62
</script>
63</body>
64</html>

js代码:
主要是两个对象,dragLayout对象(table元素) 包含 dragModule对象(可拖拽的元素)
  1 if (typeof getElementById!="function") {
  2   var getElementById = function (id) {
  3     if   (typeof(id)=="object"return id;
  4     if   (document.getElementById(id)) { return document.getElementById(id); } 
  5     else { throw new Error(id +" argument error, can not find \"" +id+ "\" element"); }
  6   }
  7 }
  8 // 获取一个element的offset信息,其实就是相对于Body的padding以内的绝对坐标
  9 function getElCoordinate (e) {
 10   var t = e.offsetTop;
 11   var l = e.offsetLeft;
 12   var w = e.offsetWidth;
 13   var h = e.offsetHeight;
 14   while (e=e.offsetParent) {
 15     t += e.offsetTop;
 16     l += e.offsetLeft;
 17   }; return {
 18     top: t,
 19     left: l,
 20     width: w,
 21     height: h,
 22     bottom: t+h,
 23     right: l+w
 24   }
 25 }
 26 
 27 var guozili = window.guozili || {}; 
 28 //整个table布局对象
 29 guozili.dragLayout = function(cfg) {
 30     this.targetId = cfg.targetId;
 31     //推拽完成时的回调函数,可以进行ajax提交
 32     this.onEnd = cfg.onEnd;
 33     this.init.apply(this);
 34 };
 35 
 36 guozili.dragLayout.prototype = {
 37     //初始化,读取每列下面的推拽模块div,并且放入dragArray数组中
 38     init : function() { with(this) {
 39         target = getElementById(this.targetId);
 40         rows = target.tBodies[0].rows[0];
 41          column = rows.cells;
 42          this.dragArray = new Array();
 43          var counter = 0;
 44          for (var i = 0; i < column.length; i ++ ) {
 45              var ele = column[i];
 46             
 47              forvar j = 0; j < ele.childNodes.length; j ++ ) {
 48              var  ele1 = ele.childNodes[j];
 49              if  (ele1.tagName == "DIV" && ele1.getAttribute("mid")) {
 50                 dragArray[counter] = new guozili.dragModule(ele1, this);
 51                 counter++ ;
 52             }
 53         }
 54         
 55     }
 56     }
 57     }
 58 };
 59 //拖拽模块div对象
 60 guozili.dragModule = function(ele, parent) {
 61     //对应的div拖拽元素
 62     this.ele = ele;
 63     //父对象,即dragLayout对象
 64     this.parent = parent;
 65     //标题栏,用于鼠标拖拽
 66     this.title = this.ele.childNodes[0];
 67     //计算拖拽element的坐标
 68     this.eleLeft = getElCoordinate(this.ele).left;
 69     this.eleTop = getElCoordinate(this.ele).top;
 70     //记录原先的邻居节点,用来对比是否被移动到新的位置 
 71     this.origNextSibling = ele.nextSibling;
 72     this.init.apply(this);
 73 };
 74 
 75 guozili.dragModule.prototype = {
 76     init : function() { with(this) {
 77         var _self = this;
 78         // 获取移动的时候那个灰色的虚线框 
 79         ghostLayer = getElementById("ghost");
 80         //鼠标按下时推拽开始
 81         title.onmousedown = function (event) {
 82               _self.dragStart(event);
 83         }
 84         title.style.cursor = "move";
 85 
 86     }
 87     },
 88     //开始拖拽设定一些位置信息
 89     dragStart: function (evt) { with(this) {
 90         var _self = this;
 91         evt  = evt?evt:window.event;
 92 
 93         var postion = getElCoordinate(ele)
 94         //鼠标相对于浏览器的位置减去元素的位置
 95         //得出鼠标相对于元素的相对位置,便于拖拽时计算元素的新位置
 96         x = evt.clientX - postion.left;
 97         y = evt.clientY - postion.top;
 98         
 99         //绝对位置,top和left就起作用了,就可以推拽了
100         ele.style.position = "absolute";
101         ele.style.top = postion.top;
102         ele.style.left = postion.left;
103         ele.style.zIndex = 100;
104         
105         //将那个灰框设定得与正在拖动的对象一样高
106         ghostLayer.style.position = "relative";
107         ghostLayer.style.display = "block";
108         ghostLayer.style.height = postion.height;
109         ghostLayer.style.width = postion.width;
110         //把灰框放到这个对象原先的位置上 
111         ele.parentNode.insertBefore(ghostLayer, ele.nextSibling);
112         
113         //鼠标按下再移动的事件,鼠标移动,元素也跟着走
114         document.onmousemove = function (event) { _self.drag(event); }
115         //释放鼠标的事件
116         document.onmouseup   = function (event) { _self.dragEnd(event);   }
117     }
118     },
119     //拖拽时实现元素跟鼠标走
120     drag: function (evt) { with(this) {
121         var _self = this;
122         evt  = evt?evt:window.event;
123         //计算元素的新的位置
124         ele.style.left = evt.clientX - x;
125         ele.style.top = evt.clientY - y;        
126         ele.style.filter = "alpha(opacity=70)" ;
127         ele.style.opacity = 0.7 ;
128         //被拖拽到的新的元素(当然也可以是原来那个) 
129         var found = null
130         //最大的距离
131          var max_distance = 10000;
132         // 遍历所有的可拖拽的element,寻找离当前鼠标坐标最近的那个可拖拽元素,以便前面插入         
133         for (var i = 0; i < parent.dragArray.length; i++)
134         {
135             var dragObj = parent.dragArray[i];
136             //利用勾股定理计算鼠标到遍历到的这个元素的距离 
137             var distance = Math.sqrt(Math.pow(evt.clientX - dragObj.eleLeft,2+ Math.pow(evt.clientY - dragObj.eleTop, 2));
138                         
139             if (isNaN(distance)){
140                  continue ;
141             }
142             //如果更小,记录下这个距离,并将它作为found 
143             if (distance < max_distance) {
144                 max_distance = distance;
145                 found = dragObj;
146             }
147             
148             
149         }
150         //找到落脚点就先把灰框插进去,我们看到的那个灰框停靠的特效
151         if  (found != null && ghostLayer.nextSibling != found.ele) {
152             found.ele.parentNode.insertBefore(ghostLayer, found.ele);
153             
154         }
155 
156         
157     }
158     },
159     //鼠标释放时推拽完成
160     dragEnd: function (evt) { with(this) {
161         var _self = this;
162         evt  = evt?evt:window.event;
163         
164         document.onmousemove = null;
165         document.onmouseup   = null;
166         //把拖拽时的position=absolute和相关的那些style都消除 
167         ele.style.position = "relative";
168         ele.style.filter = "";
169         ele.style.opacity = "";
170         ele.style.zIndex = "";
171         ele.style.left = "";
172         ele.style.top = "";
173         //将灰框隐藏起来
174         ghostLayer.style.display = "none";
175         
176         //如果现在的邻居不是原来的邻居了后者邻居就是它本身 
177         if (ghostLayer.nextSibling != origNextSibling && ghostLayer.nextSibling != this.ele) {
178             //把被拖拽的这个节点插到灰框的前面 
179             ghostLayer.parentNode.insertBefore(ele, ghostLayer.nextSibling);
180             //从新初始化可推拽元素对象,可以设定它们的新位置,为下面的拖拽操作做准备
181             parent.dragArray = null;
182             parent.init();
183             //回调函数,拖拽完成可对dragArray进行处理
184             parent.onEnd.call(this, parent.dragArray);
185             
186         }
187         
188         
189         
190         
191         
192     }
193     }
194     
195     
196 };

css代码:
 1body {
 2font-size:12px;
 3}

 4
 5#main {
 6TABLE-LAYOUT:fixed; border:1px solid #ccc;
 7}

 8
 9#main td {
10VERTICAL-ALIGN: top; WIDTH: 32% 
11}

12
13.module {
14width:100%;
15position:relative;
16border:1px solid #ccc;
17margin-bottom:10px;
18}

19
20.module .title {
21border-top:5px solid #ccc;
22background-color:#f5f5f5;
23font-size:13px;
24color:#990000;
25width:100%;
26}

27
28.module .content {
29padding:5px;
30}

31
32.block {
33width:1px; height:1px; position:relative; overflow:hidden;
34}

35
36#ghost {
37border:2px dashed #990000;
38position:absolute;
39display:none;
40top:0px;
41left:0px;
42margin-bottom:10px;
43}
posted on 2008-04-22 10:43  guozili  阅读(8749)  评论(28编辑  收藏  举报