Bootstrap Tree View,简单而优雅的树结构组件

来源:互联网 发布:军师联盟 知乎 编辑:程序博客网 时间:2024/05/08 22:51

这是Bootstrap Tree View在git上的简介。 
注意simple、elegant,简单而优雅,我喜欢这两个词。 
那么今天的实例是通过Bootstrap Tree View来制作一款省市级菜单的应用。

一、效果图

这里写图片描述 
这里写图片描述 
这里写图片描述 
这里写图片描述

二、应用

①、首先,项目需要引入bootstrap.css、jquery.js、bootstrap-treeview.js

<link type="text/css" rel="stylesheet" href="${ctx}/components/bootstrap/css/bootstrap.min.css" /><script type="text/javascript" src="${ctx}/components/jquery/jquery-1.10.1.min.js"></script><script type="text/javascript" src="${ctx}/components/treeview/js/bootstrap-treeview.js"></script>
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

②、接下来,页面上需要放一个dom元素。

<div id="procitytree" style="height: 400px;overflow-y :scroll;"></div>
  • 1
  • 1

通过设置height和overflow-y,使treeview能够在垂直方向上出现滚动条。

③、由于省市级数据一般都是固定不变的,那么页面初次加载时,我们把省市级数据先拿到。

Java端非常简单:

@RequestMapping(value = "loadProcitysInfo")public void loadProcitysInfo(HttpServletResponse response) {    logger.debug("获取所有省市");    try {        List<Provincial> provincials = provincialService.getProvincials();        for (Provincial provincial : provincials) {            List<City> citys = cityService.getCitysByProvincialId(provincial.getId());            provincial.setCitys(citys);        }        renderJsonDone(response, provincials);    } catch (Exception e) {        logger.error(e.getMessage(), e);        logger.error(e.getMessage());        renderJsonError(response, Constants.SERVER_ERROR);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这段代码需要优化,通过mybatis其实可以一次就获得省级和市级的集合。 
获取数据后,通过json写入到response中。

protected void renderJsonDone(HttpServletResponse response, final Object value) {    Map<String, Object> map = new HashMap<String, Object>();    map.put("statusCode", 200);    map.put("result", value);    String jsonText = JSON.toJSONString(map);    PrintWriter writer = null;    try {        response.setHeader("Pragma", "no-cache");        response.setHeader("Cache-Control", "no-cache");        response.setDateHeader("Expires", 0);        response.setContentType(contentType);        writer = response.getWriter();        writer.write(jsonText);        writer.flush();    } catch (IOException e) {        throw new OrderException(e.getMessage());    } finally {        if (writer != null)            writer.close();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

前端通过ajax对数据进行组装保存。

jQuery.ajax({    url : common.ctx + "/procity/loadProcitysInfo", // 请求的URL    dataType : 'json',    async : false,    timeout : 50000,    cache : false,    success : function(response) {        var json = YUNM.jsonEval(response);        if (json[YUNM.keys.statusCode] == YUNM.statusCode.ok) {            var records = json[YUNM.keys.result];            if (!json)                return;            // 城市列表都存在            if (records != null && records.length > 0) {                // 遍历子节点                $.each(records, function(index, value) {                    var proNode = {};                    // text是显示的内容                    proNode["text"] = value.proname;                    proNode["id"] = value.id;                    proNode["procode"] = value.procode;                    // 节点不可选中                    proNode["selectable"] = false;                    // 初始化市级节点                    proNode["nodes"] = [];                    $.each(value.citys, function(index, value) {                        var cityNode = {};                        cityNode["text"] = value.cname;                        cityNode["id"] = value.id;                        cityNode["proid"] = value.proid;                        cityNode["code"] = value.code;                        // 节点不可选中                        cityNode["selectable"] = false;                        proNode["nodes"].push(cityNode);                    });                    // 保存页面端对象中                    //YUNM._set.procityTreeData的数据结构就是二维数组。                    YUNM._set.procityTreeData.push(proNode);                });            }        }    }});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

④、拿到数据之后,就可以对treeview进行初始化了。

这里,我们讲一点更复杂的应用,如下图。 
这里写图片描述

如果用户已经保存过一部分节点,那么初次展示的时候就需要通过treeview展示出来了。 
我们定一些规则:

  1. 节点全部选中时color为red,check框选中。
  2. 节点未全部选中时color为red,check框未选中。
  3. 节点一个也没选中时color为默认,check框未选中。

为此,我们需要增加一点css。

/* 树形省市 */.treeview .list-group-item.node-checked {    color: red;}.treeview .list-group-item.node-selected {    color: red;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

有了这个规则,我们在初次展开treeview的时候,就需要重新制定以下数据规则。

// 省市级数据var procityTreeData = YUNM._set.procityTreeData;// 用户已经选中的城市,比如河南洛阳。var init_code = $this.next("input[name=area]").val();// 如果用户有选中项,则对选中项进行规则展示if (init_code) {    // 初始化选中项目    $.each(procityTreeData, function(index, value) {        // 通过i和省级的节点length进行对比,判断是否全选、未全选、全未选三种状态        var i = 0;        $.each(value.nodes, function(index1, value1) {            if (init_code.indexOf(value1.code) != -1) {                // 选中时先初始化state,再把state.checked设为true                value1["state"] = {};                value1["state"]["checked"] = true;                i++;            } else {                // 否则重置state,保证procityTreeData数据的不被更改                // 这个地方其实有待优化,由于js我还不算精通,所以不知道怎么把数组复制到一个新数组里,保证原始属于不被更改                value1["state"] = {};            }        });        value["state"] = {};        // 市级节点有选中,那么省级节点的状态需要变化,根据上面制定的规则来        if (i > 0) {            // 市级全选,那么此时省级节点打钩            if (value.nodes.length == i) {                value["state"]["checked"] = true;            }            // 根据selected来设定颜色            value["state"]["selected"] = true;        } else {            value["state"]["selected"] = false;        }    });}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

让treeview和我们打个招呼吧!

$("#procitytree").treeview({    data : procityTreeData,// 赋值    highlightSelected : false,// 选中项不高亮,避免和上述制定的颜色变化规则冲突    multiSelect : false,// 不允许多选,因为我们要通过check框来控制    showCheckbox : true,// 展示checkbox    }).treeview('collapseAll', {// 节点展开    silent : true});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

⑤、节点onNodeChecked、onNodeUnchecked的应用

不要⑤就够了吗? 
不够,我们还要控制节点选择框的变化。 
就像效果图中那样。 
这里写图片描述 
这里写图片描述 
这里写图片描述

onNodeChecked : function(event, node) {    YUNM.debug("选中项目为:" + node);    // 省级节点被选中,那么市级节点都要选中    if (node.nodes != null) {        $.each(node.nodes, function(index, value) {            $this.treeview('checkNode', value.nodeId, {                silent : true            });        });    } else {        // 市级节点选中的时候,要根据情况判断父节点是否要全部选中        // 父节点        var parentNode = $this.treeview('getParent', node.nodeId);        var isAllchecked = true; // 是否全部选中        // 当前市级节点的所有兄弟节点,也就是获取省下面的所有市        var siblings = $this.treeview('getSiblings', node.nodeId);        for ( var i in siblings) {            // 有一个没选中,则不是全选            if (!siblings[i].state.checked) {                isAllchecked = false;                break;            }        }        // 全选,则打钩        if (isAllchecked) {            $this.treeview('checkNode', parentNode.nodeId, {                silent : true            });        } else {// 非全选,则变红            $this.treeview('selectNode', parentNode.nodeId, {                silent : true            });        }    }},onNodeUnchecked : function(event, node) {    YUNM.debug("取消选中项目为:" + node);    // 选中的是省级节点    if (node.nodes != null) {        // 这里需要控制,判断是否是因为市级节点引起的父节点被取消选中        // 如果是,则只管取消父节点就行了        // 如果不是,则子节点需要被取消选中        if (silentByChild) {            $.each(node.nodes, function(index, value) {                $this.treeview('uncheckNode', value.nodeId, {                    silent : true                });            });        }    } else {        // 市级节点被取消选中        var parentNode = $this.treeview('getParent', node.nodeId);        var isAllUnchecked = true; // 是否全部取消选中        // 市级节点有一个选中,那么就不是全部取消选中        var siblings = $this.treeview('getSiblings', node.nodeId);        for ( var i in siblings) {            if (siblings[i].state.checked) {                isAllUnchecked = false;                break;            }        }        // 全部取消选中,那么省级节点恢复到默认状态        if (isAllUnchecked) {            $this.treeview('unselectNode', parentNode.nodeId, {                silent : true,            });            $this.treeview('uncheckNode', parentNode.nodeId, {                silent : true,            });        } else {            silentByChild = false;            $this.treeview('selectNode', parentNode.nodeId, {                silent : true,            });            $this.treeview('uncheckNode', parentNode.nodeId, {                silent : true,            });        }    }    silentByChild = true;},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

到这里,treeview的应用已经算是非常全面了,我想你一定也会应用了,不会的话,再来找我啊!

阅读全文
0 0
原创粉丝点击