zoukankan      html  css  js  c++  java
  • CSS实现树形结构 + js加载数据

      看到一款树形结构,比较喜欢它的样式,就参照它的外观自己做了一个,练习一下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图标没法加载进来,导致折叠按钮显示不出,下面是原始树状图的截图:

    数据是我用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'
    }

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

  • 相关阅读:
    [Swift]LeetCode1035.不相交的线 | Uncrossed Lines
    [Swift]LeetCode1034.边框着色 | Coloring A Border
    [Swift]LeetCode1033. 移动石子直到连续 | Moving Stones Until Consecutive
    [Swift]美人征婚问题
    [Swift]动态变化顶部状态栏(statusBar)的颜色
    [Swift-2019力扣杯春季决赛]4. 有效子数组的数目
    [Swift-2019力扣杯春季决赛]3. 最长重复子串
    [Swift-2019力扣杯春季决赛]2. 按字典序排列最小的等效字符串
    转 ORA-12638: 身份证明检索失败
    转 构建镜像
  • 原文地址:https://www.cnblogs.com/zengyuanjun/p/8903213.html
Copyright © 2011-2022 走看看