阅读文章

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

[日期:2008-04-23] 来源:  作者: [字体: ]

     Jquery的Interface elements for jQuery里面的拖拽布局存在一些bug,效率也比较低,GoogleUI google_drag.js有些乱,不是很容易理解,Discuz!NT Space代码满天飞,所以自己参考GoogleUI的思想,简化和优化了一些操作代码,实现了博客系统基本的拖拽布局的效果,暂时未考虑其他浏览器的兼容性问题。下一步准备改造成Jquery的插件形式,并增加一些渐隐渐现和动画效果,并逐步实现一些ajax的添加删除操作,嵌入基于JQuery的音乐播放器,图片浏览器,文本编辑器。
  
  预览体验:
  
  http://www.5533110.com/123/123/
  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="http://www.aspcool.com/lanmu/main.css" rel="stylesheet" type="text/css" />
   7<script src="http://www.aspcool.com/lanmu/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代码:
   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}  


阅读:
录入:blue1000

评论 】 【 推荐 】 【 打印
上一篇:asp.net 里 include UTF8 垃圾问题
下一篇:为JavaScript程序添加客户端不可见的注释
相关文章      
本文评论
发表评论


点评: 字数
姓名:

  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款