我们在项目中应用的后台管理框架基本上都是大同小异,左侧是一个二级菜单,点击选中的菜单,右侧对应的页面展示。我把前端页面封装数据的过程整理了一下,虽然不一定适合所有的管理页面,仅作为案例来参考,只是希望大家能明白实现原理就好。

  左侧的菜单的搭建:

   1、首先将我们需要应用的菜单导入数据库。

    下面的截图是我导入的数据:

    

    根据我的业务需求,我需要四个父菜单,所以我将他们的pid字段都设置为0,子菜单的pid字段对应的是父菜单的id,这很重要。url字段就是点击该菜单时,右侧页面显示的地址路径。status状态字段代表当前菜单的状态是否可用,我这里设置的0为可用,1为不可用,稍后会看到。order_num字段这里暂时用不到。

    2、封装一个构造函数来读取并创建二级菜单

    为了不使这个案例太过于繁琐,在不考虑这个构造函数的灵活性的情况下,我尽量的减少代码量。假设只是针对本案例,封装的函数如下:  

function MenuTree(id,url){
this.id = id;
this.url = url;
this.$Div = null;
this.$curA = null;
this.initTree();
} MenuTree.prototype.initTree = function(){
var self = this;
//左侧菜单的容器,根据元素的id来定义
this.$Div = $("#"+this.id);
if(this.$Div.length == 0){
alert("菜单初始化外容器失败");
return;
}
//点击方法的代理,点击这个容器时会使用this.treeClick定义的方法来代理
this.$Div.click($.proxy(this.treeClick,this));
//向设置好的菜单地址发送请求
$.post(this.url,function(data){
self.createTreeMenu(data.list);
},"json")
}
MenuTree.prototype.createTreeMenu = function(list){
//若没有读取到数据,或者数据长度为0,容器会显示暂无菜单
if(!list||list.length == 0){
this.$Div.html("暂无菜单");
return;
}
//声明一个空对象,用来存放创建的菜单信息
var rootNodes = {};
var len = list.length;
var node = null;
var curNodeId="";
for(var i=0;i<len;i++){
node = list[i];
//当读取到的菜单status为1时,代表菜单不可用,跳过
if(node.status=='1') continue;
var id = node.id;
var name = node.name;
var url = node.url;
var pid = node.pid;
//当本条数据pid为0时,创建这条数据为父菜单
if(pid == "0"){
rootNodes[id] = $("<div class='leftTreeMenu hasChildren'><leftMenuTitle>"+name+"</leftMenuTitle></div>");
continue;
}
//子菜单的pid是父菜单的id,所以这里的rootNodes[pid]就是上面的rootNodes[id]
var $pnode = rootNodes[pid];
//子菜单创建后要把id和url作为自定义属性添加到元素上面,后面会用到
var $a = $("<leftTreeNode id='leftTreeLink_"+id+"'>"+name+"</leftTreeNode>").attr("id",id).attr("url",url);
$pnode.append($a);
//这里略过不提,下一篇文章讲
if(fromURI && (url==fromURI)){
this.$curA = $a.addClass("currentA");
$pnode.addClass("currentMenu").removeClass("hideChildren");
myBar.freshTag(id,name,url);
}
}
var df = document.createDocumentFragment();
for(key in rootNodes){
//appendChild是原生js的用法
//[0]的目的是将jq的对象转换成dom对象
df.appendChild(rootNodes[key][0]);
}
(this.$Div)[0].appendChild(df);
} MenuTree.prototype.treeClick = function(e){
//click事件,会用到dom和jq的转换
var target = e.target;
var nodeName = target.nodeName;
//如果点击的是父菜单,就通过切换class名字来展示和隐藏子菜单
if(nodeName == "LEFTMENUTITLE"){
$(target).parent().switchClass("hideChildren");
return;
}
//如果点击的是子菜单,就处理子菜单的数据
if(nodeName == "LEFTTREENODE"){
this.freshTag($(target));
}
} MenuTree.prototype.changeCurNode = function($e){
//如果点击的与选中的是同一个,就return
if(this.$curA == $e) return;
//如果this.$curA存在,就将以前的类名currentA移除并子菜单隐藏
if(this.$curA){
this.$curA.removeClass("currentA").parent().removeClass("currentMenu");
}
//刚刚点击的添加类名currentA并显示子菜单
this.$curA = $e.addClass("currentA");
$e.parent().addClass("currentMenu").removeClass("hideChildren");
} MenuTree.prototype.freshTag = function($e){
//处理点击的元素
this.changeCurNode($e);
//将绑定在元素上的url取出
var url = $e.attr("url");
if(url.indexOf("http")==0 ){
window.open(url);
return;
}
//这个会在下一篇文章再讲,这里是创建右侧mybar和url页面的显示信息
myBar.freshTag($e.attr("id"),$e.html(),url);
} 

    3、JSP页面的调用

    JSP页面很简单,创建一个左侧容器id为“leftTree”,然后:

var leftTree = new MenuTree("leftTree","<c:url value='/menu/getMenuTree'/>");

    我说明一下,这篇文章只是讲解左侧菜单的读取和创建,至于点击显示对应页面准备在下一篇文章介绍。

    4、后台的处理过程    

package cn.wangze.controller;

import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes; import cn.wangze.service.SysCacheService;
import cn.wangze.service.SysMenuService; import cn.wangze.domain.SysMenu;
//import cn.wangze.service.SysMenuService;
//import cn.wangze.utils.AuthUtils; @Controller
@RequestMapping("/menu")
@SessionAttributes("sysUser")
public class SysMenuController01 extends BaseController{
Log log = LogFactory.getLog(getClass()); //将菜单的service注入控制器里面
@Resource
private SysMenuService<SysMenu> sysMenuService;
//若菜单固定的话,我们可以将数据放到缓存中,这样不用每次都从数据库请求
@Autowired
private SysCacheService sysCacheService; @RequestMapping(value = "/{pagePath}/{pageName}")
public String goMenuPage(@PathVariable String pagePath, @PathVariable String pageName,HttpServletRequest request) {
setFromURI(request);
return "/" + pagePath + "/" + pageName;
} @RequestMapping(value = "/getMenuTree")
public void getMenu(HttpServletResponse response,HttpSession session) {
//调用sysCacheService的queryMenuList方法来取数据
List<SysMenu> list = sysCacheService.queryMenuList();
log.debug("总菜单:" + list);
if (list == null) return;
//可参照我前面发的博客文章,封装的返回数据的方法,在BaseController里面
sendJsonList(list, response);
}
}

    Service和Domain层还有Mapper层的代码我就不发了,就是查询的操作,因为没有涉及到角色权限的控制,所以没有多大的难度。

  5、创建好之后的效果

   

  下一篇文章我们讲解点击子菜单,右侧显示对应地址的过程。

JavaScript处理数据完成左侧二级菜单的搭建的更多相关文章

  1. javascript 特效实现(3)—— 鼠标滑过显示二级菜单效果

    1. 关键代码:使用 switch 或 if 判断语句,改变对应的二级菜单显示方式为 block 或 none function selectTabMenu(i){ switch(i){ case 7 ...

  2. 关于expanded一级二级菜单数据的分组排序

    最新再弄关于expandedlistview相关的东西,所以需求是需要对一级菜单根据时间排序,同时二级菜单也需要根据时间排序,距离现在最近的时间显示在最前面. 效果就是如下: --group2  -- ...

  3. JavaScript(jquery)实现二级菜单联动

    为什么写这篇随笔? 二级菜单的联动一直是我心中一块石头,犹记得大一的时候只会用一点的Dreamweaver,当时做二级菜单难受啊,啥都不会,网上找了些资料,也看不懂别人的代码更别说用起来了 前些日子. ...

  4. MVC4做网站后台:栏目管理3、删除栏目与左侧列表菜单

    一.左侧列表菜单 打开视图Menu.cshtml,增加部分见红框 在category中添加脚本 //栏目菜单加载完毕函数 function CategoryMenu_Ready() { $('#cat ...

  5. jquery垂直展开折叠手风琴二级菜单

    摘要:jquery实现垂直展开二级菜单 最近新开发一个简单项目,用到左侧两级的菜单.找找了手头的文件,竟然没有现成的代码,算了,去网上找找整理下吧. 注:jquery-1.8.3.min.js需要下载 ...

  6. 使用 EasyUI 创建左侧导航菜单

    使用 JQuery EasyUI 创建左侧导航菜单,菜单的数据由后台服务提供. 效果图 HTML 元素 <div id="menuAccordion"></div ...

  7. 省市联动_简单的Demo,适用于各种二级菜单联动

    最近搞了一个功能,是查询页面需要用到二级菜单联动,获取到选中的属性value传入到后台. 平常都是用AJAX或者JQuery ,通过XML或者JSON的方式,这样的话需要调用数据库,像典型得到省市联动 ...

  8. Ionic如何实现单选二级菜单切换

    Ionic如何实现单选二级菜单切换 最近有个需求,需要做一个用户视图,数据全都从PC端系统实时取,由于这个功能在电脑浏览器展示还可以,即使菜单全部展开,只要美工稍加调整下位置也是放得下的,但是同样的功 ...

  9. Ajax和JSON完成二级菜单联动的功能

    首先需要找好JSON的包哦: 链接:http://pan.baidu.com/s/1jH6gN46 密码:lbh1 1:首先创建一个前台页面,比如secondMenu.jsp,源码如下所示: < ...

随机推荐

  1. Linux——解决RedHat6/CentOS6系统中“弹出界面eth0:设备似乎不存在”的问题

    刚刚在自己的CentOS6系统中执行service network restart时,竟然提示: 弹出界面 eth0: 设备 似乎不存在, 初始化操作将被延迟.   [失败] 这事可真神奇.于是手动编 ...

  2. 【Python3 爬虫】10_Beautiful Soup库的使用

    之前学习了正则表达式,但是发现如果用正则表达式写网络爬虫,那是相当的复杂啊!于是就有了Beautiful Soup 简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓 ...

  3. 51单片机 | SPI协议与应用实例

    ———————————————————————————————————————————— SPI总线 - - - - - - - - - - - - - - - - - - - - - - - - - ...

  4. Android ListView工作原理全然解析,带你从源代码的角度彻底理解

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android全部经常使用的原生控件其中.使用方法最复杂的应该就是 ...

  5. oracle闪回某个时间段的数据

    闪回2013-08-08 08:08:08的数据: insert into  table_1   select * from table_2 as of timestamp to_date('2013 ...

  6. 转 iOS:NSAttributedString

    NSAttributedString: http://blog.csdn.net/kmyhy/article/details/8895638 CTFramesetterSuggestFrameSize ...

  7. IIS如何添加m3u8流媒体类型

    m3u8,mime类型填写: application/x-mpegURL. ts ,mime类型填写: video/MP2T

  8. 10张思维导图带你学习【Java​Script】

    思维导图小tips:思维导图又叫心智图.是表达发射性思维的有效的图形思维工具 ,它简单却又极其有效,是一种革命性的思维工具.思维导图运用图文并重的技巧.把各级主题的关系用相互隶属与相关的层级图表现出来 ...

  9. svn的外网设置访问方法

    一.花生壳 1. 设置静态ip 选择 DHCP服务器 -> 静态地址分配,为内网内的机器分配静态ip 2.设置端口转发 选择 转发规则 -> 虚拟服务器,将外网对443端口的访问转发到安装 ...

  10. C# 泛型 default()方法

    在泛型类和泛型方法中产生的一个问题是,在预先未知以下情况时,如何将默认值分配给参数化类型 T: T 是引用类型还是值类型. 如果 T 为值类型,则它是数值还是结构. 给定参数化类型 T 的一个变量 t ...