Jquery的Interface elements for jQuery里面的拖拽布局存在一些bug,效率也比较低,GoogleUI google_drag.js有些乱,不是很容易理解,Discuz!NT Space代码满天飞,所以自己参考GoogleUI的思想,简化和优化了一些操作代码,实现了博客系统基本的拖拽布局的效果,暂时未考虑其他浏览器的兼容性问题。下一步准备改造成Jquery的插件形式,并增加一些渐隐渐现和动画效果,并逐步实现一些ajax的添加删除操作,嵌入基于JQuery的音乐播放器,图片浏览器,文本编辑器。
预览体验:
style="WIDTH: 700px; HEIGHT: 369px" src="http://www.5533110.com/123/123" width="500" height="500">
html代码:
下面的可拖拽模块的mid为其在数据库中的id号;
<div style="display:inline" mid="|"><div></div></div>
每td列最后都有一个,并隐藏起来,用来可以推拽元素到此隐藏元素的前面,或者某td列本来没有元素,
也可以拖拽到此列上面:

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44



45

46



47

48

49



50

51

52



53

54

55

56

57

58

59

60

61

62

63

64

js代码:
主要是两个对象,dragLayout对象(table元素) 包含 dragModule对象(可拖拽的元素)
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 for( var 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代码:



2

3

4

5



6

7

8

9



10

11

12

13



14

15

16

17

18

19

20



21

22

23

24

25

26

27

28



29

30

31

32



33

34

35

36



37

38

39

40

41

42

43
