Layui之动态树 左侧树形菜单栏 详细全面

简介: Layui之动态树 左侧树形菜单栏 详细全面

一.效果图

Layui就一般都为这种水墨风,哈哈,大概就是图片的左侧的样子

二.具体步骤

2.1 数据库

      需要准备的数据:首先准备好需要展示在树形菜单中的数据。这些数据应该包含节点的id、父节点id、节点名称等信息,以便构建树形结构。

2.2 树形导航栏

写一个java文件,里面包含了所有关于树形导航栏的方法和属性,把关于导航栏的单独用一个类写出,这样会更加清晰明了

   第一个类:Treevo:

       这个里面定义了许多关于父节点以及子节点的属性,可以帮助我们在将数据库的平级数据转换成父子关系的数据 ,以及定义了两个属性是否有父节点,子节点,将来要进行判断

package com.zking.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class TreeVo<T> {
  /**
   * 节点ID
   */
  private String id;
  /**
   * 显示节点文本
   */
  private String text;
  /**
   * 节点状态,open closed
   */
  private Map<String, Object> state;
  /**
   * 节点是否被选中 true false
   */
  private boolean checked = false;
  /**
   * 节点属性
   */
  private Map<String, Object> attributes;
  /**
   * 节点的子节点
   */
  private List<TreeVo<T>> children = new ArrayList<TreeVo<T>>();
  /**
   * 父ID
   */
  private String parentId;
  /**
   * 是否有父节点
   */
  private boolean hasParent = false;
  /**
   * 是否有子节点
   */
  private boolean hasChildren = false;
  public String getId() {
    return id;
  }
  public void setId(String id) {
    this.id = id;
  }
  public String getText() {
    return text;
  }
  public void setText(String text) {
    this.text = text;
  }
  public Map<String, Object> getState() {
    return state;
  }
  public void setState(Map<String, Object> state) {
    this.state = state;
  }
  public boolean isChecked() {
    return checked;
  }
  public void setChecked(boolean checked) {
    this.checked = checked;
  }
  public Map<String, Object> getAttributes() {
    return attributes;
  }
  public void setAttributes(Map<String, Object> attributes) {
    this.attributes = attributes;
  }
  public List<TreeVo<T>> getChildren() {
    return children;
  }
  public void setChildren(List<TreeVo<T>> children) {
    this.children = children;
  }
  public boolean isHasParent() {
    return hasParent;
  }
  public void setHasParent(boolean isParent) {
    this.hasParent = isParent;
  }
  public boolean isHasChildren() {
    return hasChildren;
  }
  public void setChildren(boolean isChildren) {
    this.hasChildren = isChildren;
  }
  public String getParentId() {
    return parentId;
  }
  public void setParentId(String parentId) {
    this.parentId = parentId;
  }
  public TreeVo(String id, String text, Map<String, Object> state, boolean checked, Map<String, Object> attributes,
                  List<TreeVo<T>> children, boolean isParent, boolean isChildren, String parentID) {
    super();
    this.id = id;
    this.text = text;
    this.state = state;
    this.checked = checked;
    this.attributes = attributes;
    this.children = children;
    this.hasParent = isParent;
    this.hasChildren = isChildren;
    this.parentId = parentID;
  }
  public TreeVo() {
    super();
  }
}

第二个类:BuildTree:

       这个类里面定义了两个循环,一个循环可视为外层循环,即可定义为将所有的数据循环一遍,接着第二个循环可视为内层循环,将第二个循环的父id和第一个循环的id进行判断,如果相等就说明 他们是父子关系,并且在这里还指定了默认最高节点也就是父节点,这个可根据自己的数据库里的来进行变化

package com.zking.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BuildTree {
  /**
   * 默认-1为顶级节点
   * @param nodes
   * @param <T>
   * @return
   */
  public static <T> TreeVo<T> build(List<TreeVo<T>> nodes) {
    if (nodes == null) {
      return null;
    }
    List<TreeVo<T>> topNodes = new ArrayList<TreeVo<T>>();
    for (TreeVo<T> children : nodes) {
      String pid = children.getParentId();
      if (pid == null || "0".equals(pid)) {
        topNodes.add(children);
        continue;
      }
      for (TreeVo<T> parent : nodes) {
        String id = parent.getId();
        if (id != null && id.equals(pid)) {
          parent.getChildren().add(children);
          children.setHasParent(true);
          parent.setChildren(true);
          continue;
        }
      }
    }
    TreeVo<T> root = new TreeVo<T>();
    if (topNodes.size() == 1) {
      root = topNodes.get(0);
    } else {
      root.setId("000");
      root.setParentId("0");
      root.setHasParent(false);
      root.setChildren(true);
      root.setChecked(true);
      root.setChildren(topNodes);
      root.setText("顶级节点");
      Map<String, Object> state = new HashMap<>(16);
      state.put("opened", true);
      root.setState(state);
    }
    return root;
  }
  /**
   * 指定idparam为顶级节点
   * @param nodes
   * @param idParam
   * @param <T>
   * @return
   */
  public static <T> List<TreeVo<T>> buildList(List<TreeVo<T>> nodes, String idParam) {
    if (nodes == null) {
      return null;
    }
    List<TreeVo<T>> topNodes = new ArrayList<TreeVo<T>>();
    for (TreeVo<T> children : nodes) {
      String pid = children.getParentId();
      if (pid == null || idParam.equals(pid)) {
        topNodes.add(children);
        continue;
      }
      for (TreeVo<T> parent : nodes) {
        String id = parent.getId();
        if (id != null && id.equals(pid)) {
          parent.getChildren().add(children);
          children.setHasParent(true);
          parent.setChildren(true);
          continue;
        }
      }
    }
    return topNodes;
  }
}

2.3  Dao方法

       2.3.1 basedao

package com.yinzi.utils;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.yinzi.utils.DBAccess;
import com.yinzi.utils.PageBean;
public class BaseDao<T> {
  /**
   * 带分页的模糊查询
   * @param c
   * @param sql
   * @param pagebean
   * @return
   * @throws Exception
   */
  public List<T> executeQuery(Class c ,String sql,PageBean pagebean) throws Exception{
    //创建集合保存数据
    List<T> list = new ArrayList<>();
    //获取连接
    Connection conn =null;
    //执行SQL语句
    PreparedStatement ps = null;
    //结果集对象
    ResultSet rs =null;
    //判断是否需要分页
    if(pagebean!=null && pagebean.isPagination()) {//如果需要分页,就拼接SQL语句
      String Countsql=getCountsql(sql);//获取总数量
      conn = DBAccess.getConnection();
      ps = conn.prepareStatement(Countsql);//执行改变后的SQL语句
      rs = ps.executeQuery();
      if(rs.next()) {
        pagebean.setTotal(rs.getObject("n").toString());
      }
      String pagesql=getPagesql(sql,pagebean);
      conn = DBAccess.getConnection();
      ps = conn.prepareStatement(pagesql);//执行改变后的SQL语句
      rs = ps.executeQuery();
    }else {//否则不需要,就按照原sql语句执行
      conn = DBAccess.getConnection();
      ps = conn.prepareStatement(sql);
      rs = ps.executeQuery();
    }
    //循环遍历数据
    while(rs.next()) {
      T t = (T) c.newInstance();
      //拿到所有的属性
      Field[] fields = c.getDeclaredFields();
      for (Field field : fields) {
        //打开访问权限
        field.setAccessible(true);
        field.set(t,rs.getObject(field.getName()));
      }
      list.add(t);
    }
    return list;
  }
  /**
   * 最终SQL语句
   * @param sql
   * @param pagebean
   * @return
   */
  private String getPagesql(String sql, PageBean pagebean) {
    return sql+" limit "+pagebean.getStartIndex()+","+pagebean.getRows();
  }
  /**
   * 总记录数
   * @param sql
   * @return
   */
  private String getCountsql(String sql) {
    return "select count(1) as n from ("+sql+") t";
  }
  /**
   *  增删改的方法
   * @param sql sql语句
   * @param t 实体类
   * @param attr 实体类对应的属性
   * @return
   * @throws Exception 
   */
  public int excuteUpdate(String sql ,T t,String[] attr) throws Exception {
    Connection conn=DBAccess.getConnection();//连接数据库
    PreparedStatement ps=conn.prepareStatement(sql);//执行sql语句
    //循环拿到属性
    for (int i = 0; i < attr.length; i++) {
      //一切反射从获取类类开始
      Field f = t.getClass().getDeclaredField(attr[i]);
      //打开访问权限
      f.setAccessible(true);
      ps.setObject(i+1, f.get(t));
    }
    return ps.executeUpdate();
  }
}

2.3.2 Dao类

       这个类里面首先做了一个查询所有获取所有的数据,接着 写一个方法将这些平级的数据转换成父子关系的数据,还调用了BuildTree里面的方法

package com.yinzi.dao;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yinzi.entity.Permission;
import com.yinzi.utils.BaseDao;
import com.yinzi.utils.PageBean;
import com.zking.util.BuildTree;
import com.zking.util.TreeVo;
public class PermissionDao extends BaseDao<Permission>{
  /**
   * 查詢所有
   * @param permission
   * @param pagebean
   * @return
   * @throws Exception
   */
  public List<Permission> list(Permission permission,PageBean pagebean) throws Exception {
    String sql="select * from t_easyui_permission";
    return super.executeQuery(Permission.class, sql, pagebean);
  }
  //将这些平级数据转换成父子关系的数据
  public List<TreeVo<Permission>> menus(Permission permission,PageBean pagebean) throws Exception{
    //创建一个父子关系的集合  TreeVo
    List<TreeVo<Permission>> tvList = new ArrayList<TreeVo<Permission>>();
    //获取平级数据
    List<Permission> list = this.list(permission, pagebean);
    for (Permission per : list) {
      TreeVo<Permission> tv=new TreeVo<>();
      //将per对象转成tv对象,因为tv对象才有children
      tv.setId(per.getId()+"");
      tv.setText(per.getName());
      tv.setParentId(per.getPid()+"");
      tvList.add(tv);
    }
    return BuildTree.buildList(tvList, "0");//这个地方填写一级菜单的id
  }
}

2.4  后台Servlet

package com.yinzi.Servlet;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.yinzi.dao.PermissionDao;
import com.yinzi.entity.Permission;
import com.zking.framework.ActionSupport;
import com.zking.framework.ModelDriver;
import com.zking.util.ResponseUtil;
import com.zking.util.TreeVo;
public class PermissionAction extends ActionSupport implements ModelDriver<Permission>{
  private Permission permission=new Permission();
  private PermissionDao pd=new PermissionDao();
  public void menus(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    //调用方法
    List<TreeVo<Permission>> menus = pd.menus(null, null);
    //回显给前台
    ResponseUtil.writeJson(resp, menus);
  }
  @Override
  public Permission getModel() {
    return permission;
  }
}

2.5 前台代码

      首先样式小编是复制的Layui的模式,然后在ajax里面进行了拼接循环,最后输出即可

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>后台首页</title>
<link rel="stylesheet"
  href="${pageContext.request.contextPath}/static/js/layui/css/layui.css"></link>
<script type="text/javascript"
  src="${pageContext.request.contextPath}/static/js/layui/layui.js"></script>
</head>
<body>
<div class="layui-layout layui-layout-admin">
  <div class="layui-header">
    <div class="layui-logo layui-hide-xs layui-bg-black">layout demo</div>
    <!-- 头部区域(可配合layui 已有的水平导航) -->
    <ul class="layui-nav layui-layout-left">
      <!-- 移动端显示 -->
      <li class="layui-nav-item layui-show-xs-inline-block layui-hide-sm" lay-header-event="menuLeft">
        <i class="layui-icon layui-icon-spread-left"></i>
      </li>
      <!-- Top导航栏 -->
      <li class="layui-nav-item layui-hide-xs"><a href="">nav 1</a></li>
      <li class="layui-nav-item layui-hide-xs"><a href="">nav 2</a></li>
      <li class="layui-nav-item layui-hide-xs"><a href="">nav 3</a></li>
      <li class="layui-nav-item">
        <a href="javascript:;">nav groups</a>
        <dl class="layui-nav-child">
          <dd><a href="">menu 11</a></dd>
          <dd><a href="">menu 22</a></dd>
          <dd><a href="">menu 33</a></dd>
        </dl>
      </li>
    </ul>
    <!-- 个人头像及账号操作 -->
    <ul class="layui-nav layui-layout-right">
      <li class="layui-nav-item layui-hide layui-show-md-inline-block">
        <a href="javascript:;">
          <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" class="layui-nav-img">
          tester
        </a>
        <dl class="layui-nav-child">
          <dd><a href="">Your Profile</a></dd>
          <dd><a href="">Settings</a></dd>
          <dd><a href="login.jsp">Sign out</a></dd>
        </dl>
      </li>
      <li class="layui-nav-item" lay-header-event="menuRight" lay-unselect>
        <a href="javascript:;">
          <i class="layui-icon layui-icon-more-vertical"></i>
        </a>
      </li>
    </ul>
  </div>
  <div class="layui-side layui-bg-black">
    <div class="layui-side-scroll">
      <!-- 左侧导航区域(可配合layui已有的垂直导航) -->
      <ul id="menu" class="layui-nav layui-nav-tree" lay-filter="menu">
        <li class="layui-nav-item layui-nav-itemed">
          <a class="" href="javascript:;">menu group 1</a>
          <dl class="layui-nav-child">
            <dd><a href="javascript:;">menu 1</a></dd>
            <dd><a href="javascript:;">menu 2</a></dd>
            <dd><a href="javascript:;">menu 3</a></dd>
            <dd><a href="">the links</a></dd>
          </dl>
        </li>
        <li class="layui-nav-item">
          <a href="javascript:;">menu group 2</a>
          <dl class="layui-nav-child">
            <dd><a href="javascript:;">list 1</a></dd>
            <dd><a href="javascript:;">list 2</a></dd>
            <dd><a href="">超链接</a></dd>
          </dl>
        </li>
        <li class="layui-nav-item"><a href="javascript:;">click menu item</a></li>
        <li class="layui-nav-item"><a href="">the links</a></li>
      </ul>
    </div>
  </div>
  <div class="layui-body">
    <!-- 内容主体区域 -->
    <div style="padding: 15px;">内容主体区域。记得修改 layui.css 和 js 的路径</div>
  </div>
  <div class="layui-footer">
    <!-- 底部固定区域 -->
            底部固定区域
  </div>
</div>
<script>
//JS 
layui.use(['element', 'layer', 'util'], function(){
  var element = layui.element ,
  layer = layui.layer,
  util = layui.util,
  $ = layui.$;
  $.ajax({
    url:"${pageContext.request.contextPath}/permission.action?methodName=menus",
    dataType:"json",
    success:function(data){
      console.log(data)
    //定义一个字符串进行拼接
    var htmlStr="";
    //遍历数据
    $.each(data,function(i,n){
      //拼接
      htmlStr+='<li class="layui-nav-item layui-nav-itemed">';
      htmlStr+='<a class="" href="javascript:;">'+n.text+'</a>';
      //如果其存在孩子,就在进行循环
       if(n.hasChildren){
        var children =n.children;
        //因为这个只需要循环一次,所以放在循环外面
        htmlStr+='<dl class="layui-nav-child">';
        $.each(children,function(index,node){
          //这个需要循环多次
          htmlStr+='<dd><a href="javascript:;">'+node.text+'</a></dd>';
        })
        htmlStr+='</dl>';
      } 
      htmlStr+='</li>';
    })
      $("#menu").html(htmlStr);
    //渲染
    element.render('menu'); 
    }
  });
  });
</script>
</body>
</html>

今天的分享的案例就到这啦,有不懂的宝子,评论区留言,尽情期待哦~~

相关文章
|
JavaScript 前端开发
52EasyUI 树形菜单- 树形菜单添加节点
52EasyUI 树形菜单- 树形菜单添加节点
59 0
|
前端开发 JavaScript 数据安全/隐私保护
Layui之动态树(树形菜单)详解1
Layui之动态树(树形菜单)详解1
379 0
|
设计模式 JSON 前端开发
前端框架Layui实现动态树效果(书籍管理系统左侧下拉列表)(一)
前端框架Layui实现动态树效果(书籍管理系统左侧下拉列表)
224 0
|
前端开发 JavaScript Java
前端框架Layui实现动态树效果(书籍管理系统左侧下拉列表)(二)
前端框架Layui实现动态树效果(书籍管理系统左侧下拉列表)(二)
63 0
|
2月前
|
前端开发
导航条下拉菜单的实现及思路
本文介绍了导航条下拉菜单的实现方法和思路,包括HTML结构的搭建和CSS样式的编写,通过使用hover伪类来控制下拉菜单的显示与隐藏。
导航条下拉菜单的实现及思路
|
2月前
|
JavaScript 前端开发
vue实现侧边折叠菜单栏手风琴效果
该文章介绍了如何使用Vue.js实现具有手风琴效果的侧边折叠菜单栏,包括HTML结构设计、CSS样式设置以及JavaScript交互逻辑的编写。
|
11月前
|
算法 Java
layui实现左侧导航树形菜单
layui实现左侧导航树形菜单
685 0
layui实现左侧导航树形菜单
|
6月前
|
前端开发
如何为树形菜单项添加图标?
如何为树形菜单项添加图标?
|
6月前
|
前端开发 JavaScript
左侧导航菜单
左侧导航菜单
|
6月前
|
JSON 数据库 数据格式
Layui实现树状菜单
Layui实现树状菜单
47 0