以前在用网易博客时就发现它的自定义布局功能不错,视觉上感觉也很好,虽然已经不用网易博客很多月,但一直对这个影响深刻,前几天刚看完一个不错的电视剧,心情放松,所以这两天就简单的模仿了一个,虽然是简单的模仿,不过写起来也是有点困难,至少对我自己是这样的:)
先对这个程序的相关东西说明下吧:
1,测试通过浏览器:IE6.0
2,里面用到了一些 jquery 的东西,不过整体上用的非常尴尬,因为对 jquery 实在不太熟悉,不过有时用的挺方便
下面就来大体上说说这个程序:
因为是自定义布局,所以对元素的定位,坐标等等一些东西要搞清楚,因为在 js 里面有一些看起来非常相似的属性弄的人头晕目眩,比如:event.x,event.clientX,event.offsetX 它们之间的区别。不过这些概念的讲解网上很多也很清晰,这里就不说了。下面说说这个程序的几个关键处。
关键处一:版式的动态切换
用过网易博客的应该知道网易博客的版式有很多种,对于“两列版式”就分为 “对称式”,“小大式”,“大小式”。而且除了“两列版式”还有“三列版式”,“三列版式”也分很多种。在我的程序中我只实现了“两列版式”,不过很容易扩展到“三列版式”,在后面扩展部分将说到。
其实版式的切换还是比较容易的,就是根据用户的设置然后动态改变各个控件的样式,如下:
.centerLeft
{
width:450px;
left:33px;
}
.maxLeft
{
width:600px;
left:33px;
}
<div id="weather" class="share" dragDiv="true">
<div class="divHeader">天气</div>
<div>
今 22℃~32℃ 明 22℃~30℃
</div>
</div>
拿“两列版式”的“对称式”的左边来说,如果有如上元素 $("#weather"),它初始位于版式的左边,则在 js 文件的初始函数里面就有如下语句:
$("#weather").addClass("centerLeft");
如果显示我们将版式设置为“大小式”,即版式左边大,右边小,则只需要将初始时的那个 centerLeft 样式换成相应的样式即可,这里就为 maxLeft,如下:
$("#weather").removeAttr("class"); $("#weather").addClass("share"); $("#weather").addClass("maxLeft");
当然在程序中不是这样一个个切换的,而是切换整个左边元素数组。其他的版式也是与此类似。
关键处二:拖动刚开始的半透明元素
我们在界面上拖动元素时其实拖动的不是实际本身的那个元素,而是拖动的一个在页面中一直存在的临时元素。在刚开始拖动时把实际需要拖动元素的所以属性复制给临时元素,然后设置临时元素的透明度,注册移动事件等等。当鼠标松开时再根据临时元素的当前位置判断实际需要拖动元素的新位置,并将临时元素隐藏,再改变实际需要拖动元素的位置。如在程序的 js文件里会看到这样的语句:
// 构造一个临时的悬浮DIV,相当于复制一个实际被拖动的对象 $("#tempDiv").html($(this).html()); $("#tempDiv").css({visibility:"visible",left:divLeft, top:divTop,width:this.offsetWidth, height:this.offsetHeight}); $("#tempDiv").fadeTo("fast" , 0.4 , function(){}); isMouseDown = true; $("#tempDiv").mousemove(moveFn);
关键处三:拖动完时的位置判断与重新排版
当拖动到适当位置后鼠标松开时需要根据此时的位置来重新布局,将实际需要拖动的元素移动到期望的位置,其他元素则进行相应的移动设置。在程序中我是根据鼠标松开时的鼠标位置来判断新位置的。新位置有三种:第一种是放在版式任意一边的最后,而此时版式这边本身没有其他元素;第二种也是放在版式任意一边的最后,不过此时版式这边有其他元素;第三种是放在版式任意一边的其他元素中间或是最前。这三种情况是不同的情况需要进行不同的判断,如下
// 记录数组长度 var arrayLen = leftObjs.length; // 左边数组没有元素时,即界面上左边为空的情况 if(arrayLen <= 0) { moveUp(); leftObjs[0] = activeDiv; divTop = getOffsetTop($("#pageHeader").get(0)) + $("#pageHeader").get(0).offsetHeight; } // 判断是否加在最末尾 else if(oldY >= (getOffsetTop(leftObjs[arrayLen-1]) + leftObjs[arrayLen-1].offsetHeight)) { index = arrayLen; moveUp(); // 调用该函数可能改变当前数组的长度,故需要进行判断 if(arrayLen > leftObjs.length) index--; leftObjs[index] = activeDiv; // 获得拖动元素新位置的top值 divTop = getOffsetTop(leftObjs[index-1]) + leftObjs[index-1].offsetHeight + 10; } // 放在其他元素中间的情况 else { // 再判断其他元素,略 }
程序关键的地方基本上就是处理好上面这些。因为这个程序有很大局限性,所以下面来说说程序可以扩展的地方。
扩展处一:“多列版式”
前面也说过,这个程序是实现了“两列版式”,不过扩展为“多列版式”是件容易的事,就看实际有没有这个必要了。
在程序中,版式的每一列所包含的元素(即div)都记录在相应的数组里,对于“两列版式”需要两个数组,“多列版式”就相应需要多个数组了,然后再指定相应的样式,其他地方在增加一些判断就可以了。
扩展处二:选择性显示页面控件
在网易博客里用户可以根据自己需要或意愿选择在页面上最终能够显示出来的控件,而在我这个程序中并没有这样实现,如果需要实现需要对每个能够显示的控件设置一个标识符来控制它最终是否能够显示。
扩展处三:将“单机版”改为“网络版”
这个程序是个单独的程序,里面并没有任何一处与其他服务器进行数据的交换,这样的程序在实际中肯定是没有用的,因此将其改为“网络版”是很有必要的。如果要改为“网络版”,则最开始初始化的“版式信息”,“元素信息”等等都从服务器上获取,然后再用户改动后再将数据上传到服务器保存。程序中的初始化主要是下面两个函数:
// 给装载对象布局 function layoutObjs() { // 得到初始布局高度 var initTop = getOffsetTop($("#pageHeader").get(0)) + $("#pageHeader").get(0).offsetHeight; var itTop = initTop; var i; for(i = 0 ; i < leftObjs.length ; i++) { $(leftObjs[i]).removeAttr("class"); $(leftObjs[i]).addClass("share"); $(leftObjs[i]).css({top:itTop}); itTop += leftObjs[i].offsetHeight + 10; // 根据参数动态加载布局样式 if(layout=="centerCenter") $(leftObjs[i]).addClass("centerLeft"); else if(layout == "maxMin") $(leftObjs[i]).addClass("maxLeft"); else if(layout == "minMax") $(leftObjs[i]).addClass("minLeft"); } itTop = initTop; for(i = 0 ; i < rightObjs.length; i++) { $(rightObjs[i]).removeAttr("class"); $(rightObjs[i]).addClass("share"); $(rightObjs[i]).css({top:itTop}); itTop += rightObjs[i].offsetHeight + 10; if(layout=="centerCenter") $(rightObjs[i]).addClass("centerRight"); else if(layout == "maxMin") $(rightObjs[i]).addClass("minRight"); else if(layout == "minMax") $(rightObjs[i]).addClass("maxRight"); } } // 初始化装载对象 function initObjs() { leftObjs.push($("#userInfo").get(0)); leftObjs.push($("#content").get(0)); rightObjs.push($("#time").get(0)); rightObjs.push($("#weather").get(0)); layoutObjs(); }
如果为“网络版”则 数组 push 时的数据全部从服务器上获取,layout 变量值也需要从服务器上获取。而拖动后的新数据则在相应的地方上传。
上面说了程序可以扩展的地方。下面说说这个程序的一部分不足的地方:
不足一:显示控件高度设置
程序中所有可显示控件的高度我都是最开始就设定了并且不能根据一些需要改变,所以无论在什么版式下显示控件的高度就没有发生变化,只有宽度在变。这个问题我想过不过没有好的方法解决。
不足二:没有包装成类
对于拖动元素其实可以包装成单独的类,然后把初始位置,宽度,高度以及最终位置等信息包装起来,这样操作起来比较方便,也比较清晰。不过最开始写时我没有想到。
不足三:jquery 用法尴尬
程序里面很多语句我开始都试着用 jquery 来写,不过经常因为理解而出现问题,最后还是改为基本的 js。而且在拖和放时我开始都用 jquery 里面的 show() ,hide() 等函数想实现动态效果,不过后来出来的效果却和我想象的完全两样,由此感觉 js 里面的函数执行不是串行的,不知道是不是这样:)
其实本身想说更多一点的,不过很多东西表达的不是太清楚。
后面有这个程序的下载文件,里面包含了 jquery 的 js 包,所以显得大了点。
最后希望大家能够指点一下。