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                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代码:
 1 body  {
 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}

你可能感兴趣的:(js)