CSS实现树形结构 + js加载数据

Stella981
• 阅读 1117

  看到一款树形结构,比较喜欢它的样式,就参照它的外观自己做了一个,练习一下CSS。

  做出来的效果如下:

  • 拉莫小学
    • 一年级
      • 一班
      • 二班
    • 二年级
    • 三年级
      • 一班
      • 二班
      • 三班

树的dom结构:

<div class="tree">
    <ul>
        <li>
            <span><i class="fa fa-minus-circle"></i>拉莫小学</span>
            <ul>
                <li>
                    <span><i class="fa fa-minus-circle"></i>一年级</span>
                    <ul>
                        <li><span>一班</span></li><li><span>二班</span></li>
                    </ul>
                </li>
                <li>
                    <span>二年级</span>
                </li>
                <li>
                    <span><i class="fa fa-minus-circle"></i>三年级</span>
                    <ul>
                        <li><span>一班</span></li>
                        <li><span>二班</span></li>
                        <li><span>三班</span></li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
</div>

CSS代码:

/** tree.css zyj 2018.4.21 */
ul,li{list-style-type:none;}
.tree{display:block;position:relative;padding:5px 15px;}
.tree span{display:inline-block;box-sizing:border-box;height:30px;line-height:28px;min-width:60px;text-align:center;color:#888;border:1px solid #ddd;border-radius:5px;padding:0 8px;}
.tree ul{position:relative;padding-left:60px;margin:0;}
.tree ul>li{position:relative;padding:5px 0;}
.tree>ul{padding:0;margin:0;}
/** 水平方向连线 */
.tree>ul ul>li:after{content:' ';position:absolute;top:20px;left:-45px;width:45px;border:none;border-top:1px solid #ddd;}
/** 垂直方向连线 */
.tree ul>li:not(:last-child):before{content:' ';position:absolute;top:0;left:-45px;height:100%;border:none;border-left:1px solid #ddd;}
.tree ul>li:last-child:before{content:' ';position:absolute;top:0;left:-45px;height:20px;border:none;border-left:1px solid #ddd;}
/** 控制鼠标移上去的颜色 */
.tree span:hover, .tree span:hover+ul span{color:#fff;background-color:orange;}
.tree span:hover, .tree span:hover+ul span, .tree span:hover+ul li:before, .tree span:hover+ul li:after{border-color:orange;}
/** 折叠图标 */
.tree .fa:before{margin-right:5px;}
.tree .fa-minus-circle, .tree .fa-plus-circle{cursor:pointer;}

里面引的fontawesome图标没法加载进来,导致折叠按钮显示不出,下面是原始树状图的截图:

CSS实现树形结构 + js加载数据

数据是我用JS加载的,写了个加载数据的tree.js文件,源码如下:

/** tree.js zyj 2018.4.22 */
(function(name){
    var tree, outer, defaultDateFormat;
    
    outer = {
        setData : setData,
    };
    
    defaultDateFormat = {
            unfold : true,
            name : 'name',
            childName : 'children'
    };

    function getDataFormat(dataFormat){
        var index;
        if(!dataFormat){
            return defaultDateFormat;
        }
        for(index in defaultDateFormat){
            dataFormat[index] = typeof dataFormat[index] == 'undefined'? defaultDateFormat[index] : dataFormat[index];
        }
        return dataFormat
    }
    
    function initTreeJs(name){
        var tree;
        if(checkTreeNameUsed(name)){return;}
        window[name] = outer;
        initFoldIcon($('.tree'));
    }
    
    function checkTreeNameUsed(name){
        if(window[name]){
            console.error("The window object name [" + name + "] has been used, tree.js can't be loaded! You can try another name." );
            return true;
        }
        return false;
    }
    
    function initFoldIcon(target){
        target.off('click', 'span>i.fa').on('click', 'span>i.fa', function(e){
            var ele = $(e.target);
            if(ele.hasClass('fa-minus-circle')){
                ele.removeClass('fa-minus-circle').addClass('fa-plus-circle').parent().next('ul').hide(200);
            }else if(ele.hasClass('fa-plus-circle')){
                ele.removeClass('fa-plus-circle').addClass('fa-minus-circle').parent().next('ul').show(200);
            }
        })
    }
    
    function getJqueryObjectBySelector(selector){
        var ele = $(selector);
        if(typeof selector != 'string'){
            console.error("The first parameter jquery selector [" + selector +  "] must be a string!" );
            return;
        }
        if(!ele.hasClass('tree')){
            ele = ele.find('.tree');
        }
        if(ele.length != 1){
            console.error("The selector [" + selector +  "] expect only one element!" );
            return;
        }
        return ele;
    }
    
    function setData(selector, data, dataFormat){
        var ele = getJqueryObjectBySelector(selector);
        if(!ele){return;}
        if(!data){return;}
        if(!data.length){
            data = [data];
        }
        dataFormat = getDataFormat(dataFormat);
        dataFormat.topElement = true;
        ele.empty().append(getTreeList(data, dataFormat));
        initFoldIcon(ele);
    }
    
    function getTreeList(data, dataFormat){
        var i, single, name, children, childDataFormat, 
            array = [];
        childDataFormat = dataFormat.child || dataFormat;
        if(dataFormat.unfold){
            array.push('<ul>');
        }else if(dataFormat.topElement){
            dataFormat.topElement = false;
            array.push('<ul>');
        }else{
            array.push('<ul style="display:none;">');
        }
        for(i=0; i<data.length; i++){
            single = data[i];
            if(typeof dataFormat.name == 'function'){
                name = dataFormat.name(single);
            }else if(typeof dataFormat.name == 'string'){
                name = single[dataFormat.name];
            }else{
                name = single['name'];
            }
            if(typeof dataFormat.childName == 'string'){
                children = single[dataFormat.childName];
            }else{
                children = single['children'];
            }
            array.push('<li>');
            array.push('<span>');
            if(children && children.length > 0){
                if(dataFormat.unfold){
                    array.push('<i class="fa fa-minus-circle"></i>');
                }else{
                    array.push('<i class="fa fa-plus-circle"></i>');
                }
                array.push(name);
                array.push('</span>');
                array.push(getTreeList(children, childDataFormat));
            }else{
                array.push(name);
                array.push('</span>');
            }
            array.push('</li>');
        }
        array.push('</ul>');
        return array.join('');
    }
    
    initTreeJs(name);
}('tree'))

偷懒没写注释,tree.js中目前只写了一个对外的接口 tree.setData(selector, data, dataFormat) 。参数selector是jQuery选择器,data是数据,dataFormat是数据格式。

比如加载上图的数据:

var dataTest = {
name:'拉莫小学', 
children:[
   {
       name:'一年级',
       children:[
           {name:'一班'},
           {name:'二班'}
       ]
   },
   {
       name:'二年级'
   },
   {
       name:'三年级',
       children:[
           {name:'一班'},
           {name:'二班'},
           {name:'三班'}
       ]
   }
]
};

tree.setData('.tree', dataTest);

由于后台加载的数据不一定是按照{name:'*', children:[{name:'*'},...]}这种结构,所以留了dataFormat参数,自己去定义数据格式。

简单举个例子,假如后台数据格式是

var data ={
    id : '1',
    title : '百度',
    url : 'http://www.baidu.com',
    subWeb : 
    [
         {
             id : '2',
             title : '百度新闻',
             url : 'http://news.baidu.com'
         },
         {
             id : '3',
             title : '百度知道',
             url : 'http://zhidao.baidu.com'
         },
         {
             id : '4',
             title : '百度图片',
             url : 'http://image.baidu.com'
         },
     ]
}

那么dataFormat可以定义为

var dataFormat = 
{
    name : function(data){
        return '<a href="' + data.url + '">' + data.title + '</a>';
    },
    childName : 'subWeb'
}

至于效果,读者自己去试咯。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Sass
嵌套规则(NestedRules)Sass允许将一套CSS样式嵌套进另一套样式中,内层的样式将它外层的选择器作为父选择器mainp{color:00ff00;width:97%;.redbox{
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这