1 实现效果
对于使用过CMS系统制作网站的人应该都清楚,制作网站过程有一个重要的步骤就是制作页面布局。目前,实现页面布局有两种方式:table与div。这两种方式各有其优劣之处。
Table:
优势:使用简单,使用表格进行布局顺理成章,概念和效果图理解起来很简单,制作也方便。
劣势:表格布局比较固定,布局效果控制的比较死,一些较为特殊的效果、层叠效果等比较难以实现。
Div:
优势:布局效果灵活,div能轻易的控制布局位置,浮动效果等。
劣势:操作较为复杂,需要前端布局设计人员对div的特性、层叠样式等都较为熟悉。
可以看出,其实table和div这两种布局方式是互为优劣的。但是目前来说div越来越成为一种主流设计方式,其布局效果灵活、样式新颖的特点也越来越受到青睐。而且这里我们所讲的,如果你想使用拖拽的方式轻松实现页面布局,那非div不可。如图:
如下图,可以将布局div拖入布局区,使用鼠标拖拽随意移动其位置,同时可以将其选中,使用键盘进行各个方向的位置移动,还可以delete键将其删除。另外,还可以使用鼠标拖拽其右下角改变div的大小。
双击某个div后,会弹出属性对话框。可以输入div的宽度,高度,还可以在文本区中加入div中的内容。
2 实用工具
整个工具使用jQueryUI来制作。制作过程用到了jQueryUI的包含的以下成员:
1) Accordion
用于实现左侧枫叶菜单,div来源基于此处。
2) Draggable
拖拽项即使用Draggable来实现。
3) Droppable
Droppable用来实现布局释放区。
4) Resizable
Resizable用来实现对div大小的拖拽设置效果。
5) Dialog
Dialog用来制作双击div时弹出的属性对话框。
3 实现过程
3.1 增加左侧折叠导航
增加左侧折叠导航,用到了jQueryUI中的Accordion,效果如图:
代码:
//增加折叠效果 $("#catalog").accordion( { heightStyle : "fill" }); //使<li>标签中的元素可拖拽 $("#catalog li").draggable( { appendTo : "body",//用来指定控件在拖拽过程中ui.helper的容器, 默认情况下, ui.helper使用和初始定义的draggable相同的容器, 也就是其父元素.默认值 "parent" helper : "clone" //拖拽元素时的显示方式。(如果是函数,必须返回值是一个DOM元素)可选值:"original", "clone", Function默认值 "original" });
3.2 设置布局画布
列表项已经可以拖拽了,现在还需要有地方可以接收这些元素。我们要实现的效果是,从左侧列表拖出,放入右面的布局画布区域,因此要将布局画布区域设置为接收区,jQueryUI提供了Droppable来实现这个效果:
var bordNum = 0; $("#pageAreaWrapper div") .droppable( { activeClass : "ui-state-default", hoverClass : "ui-state-hover", accept : ".item", drop : function(event, ui) { //$(this).find(".placeholder").remove(); var divContent = ""; //生成布局界面的div var ss = $("<div id=\"border_" + ++bordNum + "\" class=\"item-accepted componentWrapper\" style=\"position: absolute; z-index: 101;\">" + "<div class=\"shield\" style=\"position:absolute\">" + "</div>" + "<div class=\"wrapperBorder\" style=\"background-color: transparent; border: 0px solid transparent; opacity: 1;\">" + "<div class=\"wrapperPadding\">" + "<div class=\"wrapperContent\" style=\"width: 320px; height:240px; word-break:break-all\">" + divContent + "</div>" + "</div>" + "</div>" + "</div>"); //ss.text(ui.draggable.text()).appendTo(this); ss.appendTo(this); //获取拖入位置 var px = ui.position.left; var py = ui.position.top; //获取布局画布pageArea的在整个页面的绝对偏移量 var pageArea_px = $("#pageArea")[0].offsetLeft; //此处加上73是因为外层的table的top位置为73 var pageArea_py = $("#pageArea")[0].offsetTop + 73; //alert("cart2_px=" + cart2_px + ", cart2_py=" + cart2_py); //获取滚动条滚动距离 var scrollpx = $("#bodyOfPage").scrollLeft(); var scrollpy = $("#bodyOfPage").scrollTop(); //刚拖入时的位置,要考虑到滚动条的因素 setPosition(ss, px - pageArea_px + scrollpx, py - pageArea_py + scrollpy); ss.draggable( { containment : "#pageAreaWrapper", scroll : false, stop : function(event, ui) { } }); //双击div,编辑div内部内容 ss.dblclick(function() { var dialog; dialog = $( "#dialog-form" ).dialog({ autoOpen: false, height: 400, width: 450, modal: true, buttons: { OK: function() { var valid = true; if ( valid ) { var content = dialog.find("#content"); var divWidth = dialog.find("#divWidth"); var divHeight = dialog.find("#divHeight"); //alert(divWidth.val() + " " + divHeight.val()); ss.css('width', divWidth.val()); ss.find(".wrapperContent").css('width', divWidth.val()); ss.css('height', divHeight.val()); ss.find(".wrapperContent").css('height', divHeight.val()); ss.find(".wrapperContent").html(content.val()); dialog.dialog( "close" ); } return valid; }, Cancel: function() { dialog.dialog( "close" ); } }, close: function() { //form[ 0 ].reset(); //allFields.removeClass( "ui-state-error" ); }, open: function(event, ui) { //dialogSource = } }); //设置textarea的值需要用val()函数,html()函数设置不成功 dialog.find("#content").val(ss.find(".wrapperContent").html()); dialog.find("#divWidth").val(ss.css("width")); dialog.find("#divHeight").val(ss.css("height")); dialog.dialog( "open" ); } ); //定义点击选中事件 $("*") .click(function(event, ui) {//alert(event.currentTarget.id); //每次点击都是先取消选中,然后再让相应元素被选中 $(".selected").removeClass("selected"); if (event.currentTarget .getAttribute("class") == "shield") {//alert(1); $(this).parent().find( ".wrapperBorder").addClass( "selected"); return false; } /* else if ($(this).hasClass( "componentWrapper")) {//alert(2); $(this).find(".wrapperBorder") .addClass("selected"); }*/ //else { // $(".wrapperBorder").removeClass("selected"); //} //只激活第一次点击,之后停止起泡 //return false; }); //调整大小时同时将内层div大小调整 $(".componentWrapper").resizable( { autoHide : true, resize : function(event, ui) { //alert($(this).width()); $(this).find(".wrapperContent").css( "width", $(this).width()); $(this).find(".wrapperContent").css( "height", $(this).height()); } }); } });
这里需要说明:
1. 为了使每个被拖出来的div的id都不一样,设置了一个变量“bordNum”来标识。
2. 每个被拖出来的div,也就是ss,需要再次设置为Droppable,才能使其在画布中也能够被拖动。
3. 为了可以使用鼠标选中某个div,需要为div动态增加样式,而且要注意获取对象并动态增加了样式之后就要通过“return false”来阻止事件冒泡。
4. 刚拖入时,放入位置还要考虑到滚动条的因素。
5. 通过设置div为Resizable使其可以被拖拽调整大小。
3.3 键盘动作
键盘动作主要有选中后:
向上移动一个像素;
向下移动一个像素;
向左移动一个像素;
向右移动一个像素;
删除。
代码:
$(document).ready(function() { divFullScreen();//页面加载时全屏 $(window).bind('resize', function() { divFullScreen();//最大化,还原窗口大小时DIV尺寸跟着变化,不过最好在CSS里给这个DIV加个min-width等于html,body的最小宽度。 }); //定义键盘移动div位置事件 $(document).keydown(function(event) { var x = $(".selected").parent().position().top;//水平方向位移 var y = $(".selected").parent().position().left;//垂直方向位移 switch (event.which) { //case 37: y = y - 10; $("border_1").css("left", y + "px"); break; case 37: if (y >= 1) { //alert(y); y = y - 1; //alert(y); $(".selected").parent().css("left", y + "px"); } else { y = 0; } break; case 38: if (x > 1) { x = x - 1; $(".selected").parent().css("top", x + "px"); } else { x = 0; } break; case 39: if (y < $("#pageAreaWrapper").width() - $(".selected").width()) { y = y + 1; $(".selected").parent().css("left", y + "px"); } else { y = $("#pageAreaWrapper").width(); } break; case 40: x = x + 1; $(".selected").parent().css("top", x + "px"); break; case 46: $(".selected").parent().remove(); break; default: break; } //返回false是为了停止冒泡,以便点击键盘向下键时页面不随着移动 return false; }); });