继上一篇博客个性化定制功能后,今天我又花了足足一天时间,实现了使用js拖拽定制模块功能。主要包括三步:1.拖拽模块;2.计算坐标位置;3.完成拖拽,保存当前布局位置。
一、拖拽功能
如果只单实现简单的拖拽功能,那其实很简单,就只要注意拖拽时选中文本一些问题。由于我这里还拖拽有一些区域限制等,模块又都是从后台动态输出的,就做成一个函数类,可能实现出来就没那么通用了。拖拽的过程一般我们会用到几个事件:鼠标开始按下onmousedown事件,拖动事件onmousemove,松开鼠标完成拖拽事件onmouseup。对于几个DOM元素都有相同的事件,一般不需要每个DOM元素逐一添加事件监听,可以添加一个事件到它们公共的父元素上,这样感觉更好,然后通过事件的target或srcElement捕获触发事件源元素,这里的拖拽也是这样来实现的,onmousedown事件是监听拖拽模块的父容器元素,这个方法有点不好的就是可能获得事件发生源并不是你想要的,可能获得的是它的子元素,所以这里可能还需要额外加一个是否为parentNode的判断。onmousedown事件第一步先要判断按的元素是否为可拖拽的句柄,然后再给document添加onmousemove、onmouseup事件。onmousemove里是主要的逻辑处理的事件,先根据event事件获取鼠标位置,然后设置拖拽模块的top和left值,最后使用window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty()来取消拖拽过程中选择文本。
二、计算坐标位置
在拖拽模块过程还需要判断元素的坐标位置,因为拖动的模块只能放在指定的几个区域内,所以就需要动态判断是否在指定区域内容,在区域内的那个模块前,这些都需要根据元素的坐标来判断。先判断是否区域,区域栏为树直排列的容器,因此,只需要判断当前鼠标x坐标>=区域x坐标,并且鼠标x坐标<=区域x坐标+区域宽度即可。同理,确定区域后,判断模块是根据当前鼠标y坐标>=模块y坐标,并且鼠标y坐标<=模块y坐标+模块高度,相当于判断鼠标是否在某个元素上,依此可以定位当前拖放元素的区域模块位置,并insertBefore插入一个空元素顶位,再在onmouseup事件里把顶位的空元素替换为当前拖拽的元素,清空拖动时设置的position等样式。在拖放过程中,冒似在IE里计算还有点问题,有时候发现计算出来的位置不正确。另外还发现一个bug,在拖拽时如果用滑轮滚动页面,拖动的元素会滑落在鼠标位置,导致隔空拖动,因为拉滚动条的时候并不会触发onmousemove事件,去看了下iGoogle的首页,发现也存在这个问题,我想可能需要添加window.onscoll事件监视才能解决了。
三、保存拖拽后位置
拖拽完成onmouseup事件处理相对简单,因为在onmousemove事件中已确认拖动模块的位置了即上面所说的顶位的空元素,此时只需要replaceChild为拖拽的模块,但还有一个重要的步骤,那就是前台与后台交互,把当前客户端拖拽后的模块位置状态保存起来,或是写入进数据库。这可能就是一个比较复杂的过程了,因为这干系到数据库表存放结构等,我这里的模块表存放字段有模块ID、区域ID、排序号等,所以客户端保存的时候至少要能获取这些信息,这里我在与后台动态输出模块时就有一个约定,那就是每个模块和区域的DIV里的id或class都包含这些信息,以便客户端能用js方便取到,至于排序则是遍历模块时可自动生成一个从1开始的序号,之后在是把这些信息传递到服务端保存,发送Ajax请求这里就不罗嗦了,使用iframe也行。不过我这里两种方法都没有用,因为用户登陆进后台也可以设置所有模块的栏位和排序,前台我暂只是用Cookie来临时保存所有模块的栏位和排序,不过以后要能在前台拖拽保存所有模块的栏位和排序也很简单了,加个动态页面响应Ajax请求保存所有模块的栏位和排序写入数据库即可。
重要修复:使用添加mousewheel滚动鼠标滑轮事件修正隔空拖拽问题,但还需正确的计算出每次鼠标滑轮的距离。(2010-4-3 17:25)
事例:Drag.html
源码:(Drag.js下载)
Drag.js
1/**//*
2** Author : Jonllen
3** Create : 2010-03-21
4** Update : 2010-04-03
5** WebSite: http://www.jonllen.com/
6*/
7
8var Drag = function ( settings ) ...{
9
10for(p in this.settings)
11...{
12if ( !settings.hasOwnProperty(p) ) settings[p] = this.settings[p];
13}
14this.settings = settings;
15![]()
16![]()
17this.columns = this.settings.column ? this.getElementsByClassName(this.settings.column, this.settings.container, 'div') : document.body.childNodes;
18
19var _this = this;
20![]()
21//down
22settings.container.onmousedown = function (e)...{
23![]()
24e = window.event || e;
25![]()
26var handle = e.target || e.srcElement;
27if( !_this.hasClass(handle, _this.settings.handle) && !_this.hasClass(handle.parentNode, _this.settings.handle) )
28return;
29![]()
30handle = _this.hasClass(handle, _this.settings.handle) ? handle : handle.parentNode;
31![]()
32var mod = handle.parentNode;
33if( !_this.hasClass(mod, _this.settings.mod) )
34return;
35
36mod.style.width = mod.offsetWidth + 'px';
37mod.style.height = mod.offsetHeight + 'px';
38mod.style.border = 'dashed 2px #cdcdcd';
39mod.style.cssText += 'filter :alpha(opacity=80);opacity :0.8;';
40![]()
41if( _this.getStyle(mod, 'position') != 'absolute' )
42mod.style.position = 'absolute';
43![]()
44var y = parseInt(mod.offsetTop) - e.clientY;
45var x = parseInt(mod.offsetLeft) - e.clientX;
46![]()
47if(e.preventDefault)...{
48e.preventDefault();
49}
50![]()
51var wheelScrollTop = 0, scrollTop = -document.documentElement.scrollTop;
52var wheelEvent = function (ev) ...{
53
54ev = ev || window.event;
55var direct = 0;
56if (ev.wheelDelta) ...{
57direct = ev.wheelDelta;
58direct += direct > 0 ? -8 : 8;
59} else if (ev.detail) ...{
60//ff
61direct = -ev.detail;
62direct += direct > 0 ? 48 : -48;
63}
64![]()
65wheelScrollTop += -direct;
66if( wheelScrollTop < scrollTop )
67...{
68wheelScrollTop = scrollTop;
69}
70
71document.onmousemove(ev);
72
73};
74//fix MouseWheel Event
75_this.addEvent( document, 'mousewheel', wheelEvent );
76![]()
77var shadowElem = _this.getDragshow();
78shadowElem.style.height = mod.offsetHeight + 'px';
79shadowElem.style.border = 'dashed 2px #ccc';
80mod.parentNode.insertBefore(shadowElem, mod);
81mod.style.top = y + e.clientY + "px";
82![]()
83//move
84document.onmousemove = function(ev)...{
85![]()
86ev = window.event || ev;
87
88log(ev);
89![]()
90mod.style.top = y + ev.clientY + wheelScrollTop + "px";
91mod.style.left = x + ev.clientX + "px";
92![]()
93handle.style.cursor = 'move';
94![]()
95if( !_this.settings.shadow) return;
96![]()
97var mousePos = _this.mouseCoords(ev);
98![]()
99for(var i=0; i< _this.columns.length; i++)...{
100![]()
101var column = _this.columns[i];
102![]()
103var columnPos = _this.getPosition(column);
104var columnWidth = parseInt(column.offsetWidth);
105var columnHeight = parseInt(column.offsetHeight);
106![]()
107if( mousePos.x >= columnPos.x && mousePos.x <= (columnPos.x + columnWidth) ) ...{
108![]()
109var insertBeforeMod = column.lastChild;
110![]()
111for( var j=0; j<column.childNodes.length; j++)...{
112![]()
113var modTarget = column.childNodes[j];
114if( modTarget.nodeType == 1) ...{
115![]()
116var modTargetPos = _this.getPosition(modTarget);
117var modTargetWidth = parseInt(modTarget.offsetWidth);
118var modTargetHeight = parseInt(modTarget.offsetHeight);
119![]()
120if( (mousePos.y >= modTargetPos.y) && (mousePos.y <= modTargetPos.y + modTargetHeight) ) ...{
121insertBeforeMod = modTarget;
122break;
123}
124}
125}
126![]()
127column.insertBefore(shadowElem, insertBeforeMod);
128break;
129}
130![]()
131}
132![]()
133window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
134![]()
135};
136![]()
137//up
138document.onmouseup = function(ev)...{
139![]()
140ev = window.event || ev;
141![]()
142this.onmousemove = null;
143this.onmouseup=null;
144![]()
145handle.style.cssText = '';
146mod.style.cssText = '';
147![]()
148if( !_this.settings.shadow) return;
149![]()
150_this.removeEvent( document, 'mousewheel', wheelEvent );
151![]()
152var shadowElem = _this.getDragshow();
153if( shadowElem.parentNode.tagName != 'BODY')
154shadowElem.parentNode.replaceChild(mod, shadowElem);
155else shadowElem.parentNode.removeChild(shadowElem);
156![]()
157_this.save();
158![]()
159log('save complate!',document.cookie);
160}
161![]()
162window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
163};
164}
165
166Drag.prototype = ...{
167settings : ...{
168container : null,
169column : '',
170mod : '',
171handle : '',
172shadow : true
173},
174getStyle : function ( elem, property) ...{
175if( document.defaultView )
176...{
177var computed = document.defaultView.getComputedStyle(elem, null);
178return elem.style[property] || computed[property];
179}
180return elem.currentStyle[property];
181},
182hasClass : function (elem, name)
183...{
184return (' '+elem.className+' ').indexOf(' '+name+' ') != -1
185},
186getElementsByClassName : function (className, elem, tagName)
187...{
188elem = elem || document;
189tagName = tagName || "*";
190var results = new Array();
191var elements = elem.getElementsByTagName(tagName);
192for(var i=0; i<elements.length; i++)
193...{
194var element = elements[i];
195if( element.className && (' '+element.className+' ').indexOf(' '+className+' ') != -1 )
196results.push(element);
197}
198return results.length > 0 ? results : null;
199},
200addEvent : function(target,eventType,func)...{
201if(target.attachEvent)
202...{
203target.attachEvent("on" + eventType, func);
204![]()
205}else if(target.addEventListener)
206...{
207target.addEventListener(eventType == 'mousewheel' ? 'DOMMouseScroll' : eventType, func, false);
208}
209return this;
210},
211removeEvent : function(target,eventType,func)...{
212if(target.detachEvent)
213...{
214target.detachEvent("on" + eventType, func);
215![]()
216}else if(target.removeEventListener)
217...{
218target.removeEventListener(eventType == 'mousewheel' ? 'DOMMouseScroll' : eventType, func, false);
219}
220return this;
221},
222mouseCoords : function (ev)...{
223if (ev.pageX || ev.pageY) ...{
224return ...{
225x: ev.pageX,
226y: ev.pageY
227};
228}
229return ...{
230x: ev.clientX + document.body.scrollLeft - document.body.clientLeft,
231y: ev.clientY + document.body.scrollTop - document.body.clientTop
232};
233},
234getPosition : function (elem)...{
235var left = 0;
236var top = 0;
237
238while (elem.offsetParent)...{
239left += elem.offsetLeft;
240top += elem.offsetTop;
241elem = elem.offsetParent;
242}
243
244left += elem.offsetLeft;
245top += elem.offsetTop;
246
247return ...{x:left, y:top};
248},
249getDragshow : function ()...{
250var id = "shadow";
251var elem = document.getElementById(id);
252if( elem == null)
253...{
254elem = document.createElement('div');
255elem.id = id;
256elem.className = this.settings.mod + ' ' + id;
257document.body.insertBefore(elem, document.body.childNodes[0]);
258}
259return elem;
260},save : function () ...{
261var sort = 1;
262var cookieArr = new Array();
263for(var i=0; i<this.columns.length; i++) ...{
264var column = this.columns[i];
265for( var j=0; j< column.childNodes.length; j++) ...{
266var mod = column.childNodes[j];
267if( mod.nodeType == 1 && this.hasClass(mod, this.settings.mod) ) ...{
268var columnId = column.className.substring(column.className.length - 1);
269var modId = mod.id.replace(this.settings.mod,'');
270cookieArr.push( modId + '=' + columnId + '-' + sort );
271sort++;
272}
273}
274}
275this.cookie('Drag',cookieArr.join('&'),10);
276},cookie : function (name, value, expires)
277...{
278var date = new Date();
279if( expires )
280...{
281date.setTime(date.getTime() + 1000 * 60 * expires );
282}
283![]()
284document.cookie = name + '=' + value + '; path=/; expires=' + ( expires ? date.toGMTString() : '0' );
285}
286}
287
288function log(obj)
289...{
290if( typeof(enableLog) == 'undefined' ) return;
291![]()
292var id = 'log';
293var logElem = document.getElementById(id);
294if( logElem == null )
295...{
296logElem = document.createElement('div');
297logElem.id = id;
298logElem.style.cssText = 'position:fixed !important;position:absolute;z-index:9999;bottom:2px;left:2px;border:solid 2px #ccc;background-color:#e0e54b;opacity:0.5;filter:alpha(opacity:50);color:red;font-weight:700;overflow-x:hidden;overflow-y:auto;';
299![]()
300document.body.insertBefore(logElem, document.body.childNodes[0]);
301}
302logElem.style.display = 'block';
303logElem.innerHTML = '';
304for(var i=0;i < arguments.length; i++)
305...{
306var obj = arguments[i];
307logElem.innerHTML += '<b>'+obj+'</b><br />';
308for(var p in obj)
309...{
310logElem.innerHTML += p + ':' + obj[p] + '<br />';
311}
312}
313logElem.style.height = logElem.clientHeight > 500 ? "500px" : "auto";
314![]()
315}
316
317new Drag(...{
318container : document.getElementById('main'),
319column : 'column',
320mod : 'mod',
321handle : 'head'
322});
能否给我发个有几个简单asp.net页面的完整例子呢,谢谢啦
crs811@qq.com
若方便,能否将保存数据库的过程也顺便说一下呢,谢谢
谢谢!
email:liulei051610613@126.com
谢谢啦