控制台 反馈

一个简单的JS/CSS3组织架构生成DEMO

发布/小网 数据源/原创
用CSS3 JAVASCRIPT 动态生成组织架构的DEMO
概述

因业务需要,需要做一个类似组织架构的树型结构生成工具,效果如下:

1526604373382.jpg

考虑到数据内容会动态变化,而且节点层级是动态的。用canvas生成难度和复杂度相对较大,而且要各种计算,后来就直接用css3来实现。用CSS3来实现就可以简单的解决前面的几个动态因素引起的问题,实现起来还是挺简单的。具体见下面的示例代码(需要支持flex的浏览器环境)。

核心样式
html{
  background-color: #f3f3f3;
}
body{
  color: #333;
  font-size: .24rem;
}
html.fixedpage{
  width: 100%;
  height: 100%;
  max-height: 100%;
  /*overflow: hidden;*/
  display: block;
}
html.fixedpage body{
  width: 100%;
  height: 100%;
  max-height: 100%;
  /*overflow: hidden;*/
  display: block;
}
html.fixedpage .app-body{
  overflow: hidden;
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
  display: block;
}
html.fixedpage.fxbottom .app-body{
  height: -webkit-calc(100% - .98rem);
  height: -moz-calc(100% - .98rem);
  height: -ms-calc(100% - .98rem);
  height: calc(100% - .98rem);
}
html.fixedpage.fxtop .app-body{
  height: -webkit-calc(100% - .88rem);
  height: -moz-calc(100% - .88rem);
  height: -ms-calc(100% - .88rem);
  height: calc(100% - .88rem);
}
html.fixedpage.fxboth .app-body{
  height: -webkit-calc(100% - .88rem - .98rem);
  height: -moz-calc(100% - .88rem - .98rem);
  height: -ms-calc(100% - .88rem - .98rem);
  height: calc(100% - .88rem - .98rem);
}
.app-header{
  width: 100%; 
  position: relative; 
  z-index: 20;
}
.app-body{
  width: 100%; 
  position: relative; 
  z-index: 10;
}
.app-footer{
  width: 100%; 
  position: relative; 
  z-index: 20;
}
html.fixedpage{
  width: initial;
  height: initial;
  max-height: initial;
  display: initial;
}
html.fixedpage body{
  width: initial;
  height: initial;
  max-height: initial;
  display: initial;
}
html.fixedpage .app-body{
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  display: block;
}
.root{
    /*position: absolute;
    left: 0;
    top: 0;*/
    position: relative;
    margin-top: .40rem;
}
.node{
    margin: 0 .20rem;
    position: relative;
}
.root > .node::before{
    content: none!important;
}
.root > .node > .node-data::before{
    content: none!important;
}
.node::before{
    content: "";
    display: block;
    height: .20rem;
    width: -webkit-calc(100% + .40rem);
    border-top:  1px solid #565596;
    position: absolute;
    top: -.20rem;
}
.node:first-child::before{
    content: "";
    display: block;
    height: .20rem;
    width: -webkit-calc(50% + .20rem);
    /*border-left: 1px solid #565596;*/
    border-top:  1px solid #565596;
    position: absolute;
    top: -.20rem;
    left: 50%;
}
.node:last-child::before{
    content: "";
    display: block;
    height: .20rem;
    width: -webkit-calc(50% + .20rem);
    /*border-right: 1px solid #565596;*/
    border-top:  1px solid #565596;
    position: absolute;
    top: -.20rem;
    right: 50%;
}
.node:only-child::before{
    content: "";
    border-top: 0;
    border-right: 0;
    margin-left: -1px;
}
.node-data{
    border: 1px solid #565596;
    background-color: #fff;
    color: #565596;
    width: 2.00rem;
    text-align: center;
    border-radius: .10rem;
    position: relative;
}
.node-data::before{
    content: "";
    display: block;
    height: .20rem;
    width: 0;
    border-left: 1px solid #565596;
    position: absolute;
    top: -.20rem;
    left: 50%;
    margin-left: -1px;
}
.node-data::after{
    content: "";
    display: block;
    height: .20rem;
    width: 0;
    border-left: 1px solid #565596;
    position: absolute;
    top: 100%;
    left: 50%;
    margin-left: -1px;
}
.node-data.no-children::after{
    content: none;
}
.node-data h2{
    font-weight: normal;
    font-size: .24rem;
    line-height: 1.7;
}
.node-data p{
    font-size: .24rem;
    color: #666;
    line-height: 1.5;
}
.node-children{
    margin-top: .40rem;
    position: relative;
}
/*.node-children::before{
    content: "";
    display: block;
    width: 50%;
    height: .20rem;
    position: absolute;
    top: -.20rem;
    left: 25%;
    border: 1px solid #565596;
    border-bottom: 0;
}*/


核心HTML模板代码
  <script type="text/template" id="tpl0">
    <~
    var node = rd.node;
    var children = rd.children;
    ~>
    <div class="node flexbox middle center vertical nowrap">
      <div class="node-data<~=children && children.length > 0 ? '' : ' no-children'~>">
        <h2><~=node.userName~></h2>
        <p>ID:<~=node.money~></p>
      </div>
      <div class="node-children flexbox top center">
        <~
        for(var i = 0; i < children.length; i++){
        var child = children[i];
        ~>
        <div class="node flexbox middle center vertical nowrap">
          <div class="node-data<~=child.children && child.children.length > 0 ? '' : ' no-children'~>">
            <h2><~=child.node.userName~></h2>
            <p>ID:<~=child.node.money~></p>
          </div>
          <div class="node-children flexbox top center">
            <~=_children(child.children)~>
          </div>
        </div>
        <~
        }
        ~>
      </div>
    </div>
  </script>
  <div class="root flexbox top left">
    
  </div>


数据结构代码
var data = {
    "node": {
        "userName": "小网UU",
        "money": 1234
    },
    "children": [
        {
            "node": {
                "userName": "1234",
                "money": 1234
            },
            "children": [
                {
                    "node": {
                        "userName": "1234",
                        "money": 1234
                    },
                    "children": [
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                },
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                }
                            ]
                        },
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                },
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                }
                            ]
                        }
                    ]
                },
                {
                    "node": {
                        "userName": "1234",
                        "money": 1234
                    },
                    "children": [
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                },
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                }
                            ]
                        },
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                },
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                }
                            ]
                        },
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                },
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                }
                            ]
                        },
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                },
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        {
            "node": {
                "userName": "1234",
                "money": 1234
            },
            "children": [
                {
                    "node": {
                        "userName": "1234",
                        "money": 1234
                    },
                    "children": [
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [                            ]
                        },
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [                            ]
                        }
                    ]
                },
                {
                    "node": {
                        "userName": "1234",
                        "money": 1234
                    },
                    "children": [
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [                            ]
                        },
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [                            ]
                        }
                    ]
                }
            ]
        },
        {
            "node": {
                "userName": "1234",
                "money": 1234
            },
            "children": [
                {
                    "node": {
                        "userName": "1234",
                        "money": 1234
                    },
                    "children": [
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [                            ]
                        },
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [                            ]
                        }
                    ]
                },
                {
                    "node": {
                        "userName": "1234",
                        "money": 1234
                    },
                    "children": [
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [                            ]
                        },
                        {
                            "node": {
                                "userName": "1234",
                                "money": 1234
                            },
                            "children": [
                                {
                                    "node": {
                                        "userName": "1234",
                                        "money": 1234
                                    },
                                    "children": [
                                        {
                                            "node": {
                                                "userName": "1234",
                                                "money": 1234
                                            },
                                            "children": [                                            ]
                                        },
                                        {
                                            "node": {
                                                "userName": "1234",
                                                "money": 1234
                                            },
                                            "children": [                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
};


核心业务代码
var oTemplateEngine = (function(){
    var Util = {
      /**
         * 执行回调
         * @param Object handler {Function callback, Array args, Object context, int delay}
         * @param * __args 附加参数,些参数将会置于 handler.args 之前
         */
        execHandler : function(handler, __args){
            if(handler && handler instanceof Object){
                var callback = handler.callback || null;
                var args = [].concat(handler.args || []);
                var context = handler.context || null;
                var delay = handler.delay || -1;                if(__args){
                    __args = [].concat(__args);                    args = __args.concat(args);
                }                if(callback && callback instanceof Function){
                    if(typeof(delay) == "number" && delay >= 0){
                        if(callback.tid){
                            clearTimeout(callback.tid);
                            callback.tid = undefined;
                        }                        return (callback.tid = setTimeout(function(){
                            callback.apply(context, args);
                        }, delay));
                    }else{
                        return callback.apply(context, args);
                    }
                }
            }
        },
        getTime: function(){
            return Date.now ? Date.now() : (new Date().getTime());
        }
    };
    //options::start 启始标签
    //options::close 结束标签
    //options::handle 渲染后回调函数
    //options::root 模板渲染时的本地对象空间
    var _Template = function(name, options){
        this.name = name;
        this.options = options; 
        this.start = options.start || "<%";
        this.close = options.close || "%>";
        this.handle = options.handle || null;
        this.root = options.root || "obj";
    };    _Template.TPLCache = {};
    _Template.Cache = {};    _Template.prototype = {
        /**
         * 模板渲染
         * @param boolean isDirect 是否为直接量,true: tplId为模板片断, false: tplId为模板容器ID
         * @param String tplId 模板或模板容器ID
         * @param Object metaData 模板数据
         * @param Object handle 渲染回调
         * @return Object ret {Object global, Object local}
         */
        render: function(isDirect, tplId, metaData, handle){
            var tpl = (true === isDirect ? tplId : (_Template.TPLCache[tplId] || (_Template.TPLCache[tplId] = $("#" + tplId).html())));            return (function(_t, str, data, callback){
                // Generate a reusable function that will serve as a template
                // generator (and which will be cached).
                var startTime = Util.getTime();
                var chr = function(str){
                    var tmp = "";
                    for(var i = 0, size = str.length; i < size; i++){
                        tmp += "\\" + str.charAt(i);
                    }                    return tmp;
                };
                var template = str;
                var fn = new Function(
                    _t.root,
                    "var p=[],print=function(){p.push.apply(p,arguments);};" +                    // Introduce the data as local variables using with(){}
                    "with(" + _t.root + "){p.push('" +
                    //------------------------------------
                        // Convert the template into pure JavaScript
                        str
                            .replace(/[\r\t\n]/g, " ")
                            .split(_t.start).join("\t")
                            .replace(new RegExp("((^|" + chr(_t.close) + ")[^\\t]*)'", "g"), "$1\r")
                            .replace(new RegExp("\\t=(.*?)" + chr(_t.close), "g"), "',$1,'")
                            .split("\t").join("');")
                            .split(_t.close).join("p.push('")
                            .split("\r").join("\\'")
                    //------------------------------------    
                    + "');}return p.join('');"
                );                // Provide some basic currying to the user
                var result =  data ? fn( data ) : str;
                var endTime = Util.getTime();
                var elapsedTime = endTime - startTime;
                var o = {
                    "result": result,
                    "elapsedTime": elapsedTime,
                    "template": template,
                    "metaData": metaData
                };
                var ret = {
                    "global": undefined,
                    "local": undefined
                };                if(_t.handle){
                    ret["global"] = Util.execHandler(_t.handle, [o]); //全局
                }
                if(callback){
                    ret["local"] = Util.execHandler(callback, [o]);  //局部
                }                return ret;
            })(this, tpl, metaData, handle);
        }
    };    return {
        "version": "R17B0817",
        getTemplate: function(name, options){
            var _t = _Template.Cache[name] || (_Template.Cache[name] = new _Template(name, options || {}));            return {
                render: function(isDirect, tplId, metaData, handle){
                    var ret = _t.render(isDirect, tplId, metaData, handle || null);
                    var eng = this;                    eng["global"] = ret["global"];
                    eng["local"] = ret["local"];                    return eng;
                }
            }
        }
    };
})();
/////////////////////////////////////////////////////////
function _children(items){
    var size = items.length;
    var html = "";    var ote = oTemplateEngine.getTemplate("ote", {
        "start": "<~",
        "close": "~>",
        "root": "rd"
    });    for(var i = 0; i < size; i++){
        var item = items[i];        html += ote.render(false, "tpl0", item, {
            callback: function(ret){
                return ret.result;
            }
        }).local
    }    return html;
};
(function(){
    var ote = oTemplateEngine.getTemplate("ote", {
        "start": "<~",
        "close": "~>",
        "root": "rd"
    });    ote.render(false, "tpl0", data, {
        callback: function(ret){
            $(".app-body").find(".root").html(ret.result);
        }
    });    setTimeout(function(){
        var body = document.querySelector(".app-body");
        var node = document.querySelector(".root > .node");
        var rect = node.getBoundingClientRect();
        var width = rect.right - rect.left;        body.scrollLeft = (width / 2) - window.innerWidth / 2;
    }, 60);
})();