首页 > 技术文章 > treeview-树形菜单js组件编写及应用

cheerup 2016-11-14 11:09 原文

简要介绍:  

  之前手头的一个项目需要去做一个左侧的树形菜单,右侧则是一个整体的iframe,从而构成一个整体的网站。一开始是打算用bootstrap的tree-view插件,直接把菜单的数据传过去就好了,结果后来项目又改了需求,菜单的内容和图表都是后台动态生成的,所以只能放弃使用bootstrap插件,自己着手写了一个树形菜单。本文主要分两部分讲,一个是对于bootstrap的treeview的实践,另一部分是介绍自己写的树形菜单。

 

bootstrap-treeview:

组件介绍http://www.htmleaf.com/jQuery/Menu-Navigation/201502141379.html

  其实关于该组件在其他网站上已经讲得很详细了,我就不再赘述了,但是网上的应用还是有点问题,这里主要讲一下自己使用这个插件过程吧。

  1. html引用及结构

  引用css:文件本身的css文件、bootstrp.css文件

  引用js:jquery、bootstrap-treeview.js、引用该组件的treeview.js文件

  整体HTML结构主要分为了三个部分:头部、树状栏部分、iframe部分,使用组件的为树状栏部分:#tree

  2.引用组件js设置:

  具体设置代码如下:主要思路是用data传入菜单的数据和依靠关系,同时可以设置一些变量来控制改树状栏的样式和基本功能,如代码40-43行,具体变量对应的数值的意义可以参见之前链接中的表格

 1 (function(win) {
 2     
 3         var data = [
 4           {
 5             text: "Parent 1",
 6             nodes: [
 7               {
 8                 text: "Child 1",
 9                 nodes: [
10                   {
11                     text: "Grandchild 1"
12                   },
13                   {
14                     text: "Grandchild 2"
15                   }
16                 ]
17               },
18               {
19                 text: "Child 2"
20               }
21             ]
22           },
23           {
24             text: "Parent 2"
25           },
26           {
27             text: "Parent 3"
28           },
29           {
30             text: "Parent 4"
31           },
32           {
33             text: "Parent 5"
34           }
35         ];          
36     
37     var tree = function() {
38         $('#tree').treeview({
39              data: data,
40               backColor: '#293541',
41               color: 'white',
42               onhoverColor:'#202a33;',
43               showBorder: false
44             });    
45     }
46      
47     var init = function() {
48         tree();
49     }
50     
51     init();
52 })(window)

  设置完成之后树状栏的样式如下图所示,另外细节方面可以通过阅读相应参数来设置,值得一提的是树状栏的icon图标是通过bootstrap的glyphicon设置的,有兴趣的童鞋可以去看一下这个东西,来为菜单设置不同的icon,不过实际效果感觉不是特别好。这也是我决定自己去搞一个树状栏的原因。

 

 

  

  自定义树状菜单:

  treeview的插件只能点击菜单前面的加号icon展开关闭,样式的变化有限,而且我们需要根据后台传入的数据来动态设置菜单的结构和内容,所以为了满足这几个需求,重新写了一个tree.js

  js主要分成三个部分,第一个部分是为每个菜单和子菜单注册点击事件以及通过后台传来的数据为其绑定跳转链接;第二个部分是通过ajax获取后台传来的菜单数据,并将数据传入前台;第三个部分是通过underscore的template函数将前台页面进行渲染,达到动态实现树状栏的功能。、

  相关js代码:

 

  1     var tree = function() {
  2         //一级导航点击事件
  3         $('.nodeBox').on('click', function(event) {
  4             var _this = $(this);
  5             var child = _this.parent().find('.nodechild_box');
  6             if (_this.attr('opened') == 'opened') {
  7                 _this.parent().find('.childnode').hide();
  8                 child.hide();
  9                 _this.attr('opened', '');
 10             }else{
 11                 _this.parent().find('.childnode').show();
 12                 child.show();
 13                 _this.attr('opened', 'opened');
 14             };
 15         });
 16         //二级导航点击事件
 17         $('.nodechild_box').on('click', function(event) {
 18             var _this = $(this);
 19             var child = _this.parent().find('.gchild_box');
 20             if (_this.attr('opened') == 'opened') {
 21                 child.hide();
 22                 _this.parent().find('.gchildnode').hide();
 23                 _this.find('.add').attr('src', 'images/icon_add.png');
 24                 _this.attr('opened', '');
 25             }else{
 26                 child.show();
 27                 _this.parent().find('.gchildnode').show();
 28                 _this.find('.add').attr('src', 'images/icon_minus.png');
 29                 _this.attr('opened', 'opened');
 30             };
 31         });
 32         //三级导航点击事件
 33         $('.gchild_box').on('click', function(event) {
 34             var _this = $(this);
 35             var child = _this.parent().find('.ggchild_box');
 36             if (_this.attr('opened') == 'opened') {
 37                 child.hide();
 38                 _this.find('.add').attr('src', 'images/icon_add.png');
 39                 _this.attr('opened', '');
 40             }else{
 41                 child.show();
 42                 _this.find('.add').attr('src', 'images/icon_minus.png');
 43                 _this.attr('opened', 'opened');
 44             };
 45         });
 46 
 47         //hover显示箭头及背景变化
 48         $('.nodeBox').mouseover(function(event) {
 49             $(this).addClass('tree_hover');
 50             $(this).find('.arrow').show();
 51         });
 52         $('.nodeBox').mouseout(function(event) {
 53             $(this).removeClass('tree_hover');
 54             $(this).find('.arrow').hide();
 55         });
 56         $('.nodechild_box').mouseover(function(event) {
 57             $(this).addClass('box_hover');
 58             $(this).find('.arrow').show();
 59         });
 60         $('.nodechild_box').mouseout(function(event) {
 61             $(this).removeClass('box_hover');
 62             $(this).find('.arrow').hide();
 63         });
 64         $('.gchild_box').mouseover(function(event) {
 65             $(this).addClass('box_hover');
 66             $(this).find('.arrow').show();
 67         });
 68         $('.gchild_box').mouseout(function(event) {
 69             $(this).removeClass('box_hover');
 70             $(this).find('.arrow').hide();
 71         });
 72         $('.ggchild_box').mouseover(function(event) {
 73             $(this).addClass('box_hover');
 74             $(this).find('.arrow').show();
 75         });
 76         $('.ggchild_box').mouseout(function(event) {
 77             $(this).removeClass('box_hover');
 78             $(this).find('.arrow').hide();
 79         });
 80     };
 81     
 82     //链接函数
 83     var tree_link = function() {
 84         
 85         var linkBox = $('[menurl]');
 86         linkBox.each(function(i, ele) {
 87             var _ele = $(ele);
 88             var key = _ele.attr('menurl');
 89             if(key != '/'){
 90                 $(this).on('click',function(){
 91                     $('#mainweb').attr('src', key);
 92                     auto();
 93                 })    
 94             }
 95             
 96         });
 97     };
 98     
 99     //获取登陆用户数据
100     var getData = function() {
101         var cond = sessionStorage.cond; 
102         
103         $.post("XXXX", {}, function(json) {
104             console.log(json)
105             if(json.code == 200){
106                 data = json.data;
107                 fillUserName(data);
108                 fillTree(data);
109                 var length = $('.nodeBox').length ;
110                 for (var i = 0;i < length;i++) {            
111                     var iconId = data.icons[i].iconId;
112                     $('.nodeBox').eq(i+1).attr('menuid',i);
113                     $('.nodeBox').eq(i+1).find('img').attr('src','images/'+ data.icons[iconId-1].name +'');
114 
115                 }
116                 //为每个菜单添加链接
117                 tree_link()
118             }
119         }, function(xhr) {
120             console.log(xhr)
121         });
122 
123     }
124     
125     
126     var fillTree = function(data){
127         var tmplDom = $('#tree');
128         tmplDom.parent().html(eking.template.getHtml(tmplDom.html(),data));
129         tree();
130     }

 

  HTML渲染:

 

 

 1     <div class="main w_1200">
 2         <div class="tree">
 3         <script type="text/html" id="tree">
 4             <div class="tree_box">
 5                 <div class="nodeBox index" menurl="notice.html">
 6                     <span class="m_l_10"><img src="images/icon_home.png" alt=""></span>
 7                     <span class="m_l_10">首页</span>
 8                     <span class="arrow fr m_r_10"><img src="images/icon_arrow.png" alt=""></span>
 9                 </div>
10             </div>
11             <%var menus = data.menus;%>
12             <%for(var i = 0;i < menus.length;i++){%>
13             <div class="tree_box">
14                 <div class="nodeBox" menurl=<%=menus[i].url%> >
15                     <span class="m_l_10"><img src="" alt=""></span>
16                     <span class="m_l_10"><%=menus[i].name%></span>
17                 </div>
18                 <%var childmenus = menus[i].childs;%>
19                 <%for(var j = 0;j < childmenus.length;j++){%>
20                 <div class="childnode">
21                     <div class="nodechild_box" menurl=<%=childmenus[j].url%> >
22                         <%if(childmenus[j].childs.length != 0){%>
23                         <span class="m_l_20"><img class="add" src="images/icon_add.png" alt=""></span>
24                         <span class="m_l_10"><%=childmenus[j].name%></span>
25                         <%}else{%>
26                         <span class="m_l_55"><%=childmenus[j].name%></span>
27                         <span class="arrow fr m_r_10"><img src="images/icon_arrow.png" alt=""></span>
28                         <%}%>
29                     </div>
30                     <%var cchildmenus = childmenus[j].childs;%>
31                     <%for(var k = 0;k < cchildmenus.length;k++){%>
32                     <div class="gchildnode">
33                         <div class="gchild_box" menurl=<%=cchildmenus[k].url%> >
34                             <%if(cchildmenus[k].childs.length != 0){%>
35                             <span class="m_l_30"><img class="add" src="images/icon_add.png" alt=""></span>
36                             <span class="m_l_10"><%=cchildmenus[k].name%></span>
37                             <%}else{%>
38                             <span class="m_l_65"><%=cchildmenus[k].name%></span>
39                             <span class="arrow fr m_r_10"><img src="images/icon_arrow.png" alt=""></span>
40                             <%}%>
41                         </div>
42                         <%var ccchildmenus = cchildmenus[k].childs;%>
43                         <%for(var l = 0;l < ccchildmenus.length;l++){%>
44                         <div class="ggchild_box" menurl=<%=ccchildmenus[l].url%> >
45                             <span class="m_l_70"><%=ccchildmenus[l].name%></span>
46                             <span class="arrow fr m_r_10"><img src="images/icon_arrow.png" alt=""></span>
47                         </div>
48                         <%}%>
49                     </div>
50                     <%}%>
51                 </div>
52                 <%}%>
53             </div>
54         <%}%>
55         </script>
56         </div>

 

  后台传入的数据格式为

  

  菜单效果如图:

  

 

   存在的不足和问题

  为了跟上项目进度,tree.js尚未组件化,等有时间了打算把这一块封装为一个js组件,通过设置参数完成树状栏的设置。

  P.S.由于个人技术水平有限,难免出现错误,请多多指正 :)

 

推荐阅读