好多的博客都有拖拽和添加,删除模块的效果,我想请高手指点一下,那些效果是怎么实现的,还有模块拖拽后的状态是怎么保存的?麻烦说的详细点!

解决方案 »

  1.   

    去看看portal的代码吧,这个已经是很基础的东西了,虽然我自己没亲自弄过。哈哈!
      

  2.   

    要是我自己做的话,我就用js附和着dwr或者jquery来实现。
    拖拽并不难实现,网上很多现成js代码
    主要是ajax和数据库交互了
      

  3.   

    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>
      

  4.   

    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:
    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}
      

  5.   

    portlet吧,用户可以自己添加删除portlet,也可以拖拽它到其他地方
      

  6.   

    搜狐那样的,用siteMesh实现挺方便的