js控件封装之tree

今天重新整理以前封装的树结构控件,用弹性布局替代了宽度计算,支持实时响应宽度改变,并且添加了事件回调等配置项,同时修复了一些遗留的bug

<!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
    <title>test</title>
    <script type="text/javascript" src="../js/jquery-3.1.1.min.js"></script>
    <style type="text/css">
        html,body{ margin:0;padding:0;width:100%;height:100%; }
    </style>
</head>
<body>
    <div id="testTree" style="width:200px;height:600px;margin:50px;border: 1px solid red"></div>
</body>
</html>
<script type="text/javascript">

if (typeof jQuery === 'undefined') { throw 'no jquery'; }
(function () {
    window.UETree = function (container, data, config) {
        //私有属性
        var parent         = $('<div></div>'),
            defaultConfig  = {
                isOpen: false,               //是否展开
                hasCreate: false,            //是否显示添加、删除按钮
                hasCheckbox: false,          //是否显示勾选框
                flagType: 'addReduce',       //采用何种图标样式,默认加减符号,file\triangle\addReduce
                flags: {                     //图标样式,可提供实心三角形、加减符、文件与文件夹等选项
                    triangle: {
                        top: 4,
                        open:  'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAABPSURBVDhPY/wPBAwUACYoTTYYNYCBASUWEhISoCzcYMGCBVAWBKC4AF0SHWCTx/ACLkNwiWMNA3TFeF0GCgNcID4+HsrCDUaTMsUGMDAAAKIFWDAh58ynAAAAAElFTkSuQmCC',
                        close: 'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAABRSURBVDhPY/wPBAwUACYoTTYYxAYkJCRAWfgBXhcQYwhBLxAyhKgwwGcI0YGIyxCiDViwYAGUhQqIMgCXZhAgaAA+zSCA1wBCmkFgyGcmBgYAX8sVNxW3k9cAAAAASUVORK5CYII=',
                        leaf:  ''
                    },
                    addReduce: { open: '+', close: '-', leaf: '' },
                    file: {
                        top: 4,
                        open: 'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAB7SURBVDhPY/wPBAwUACYoTTZAccGTI8VQFiqQsemFsjAB3ACQZmlzJ7AgOnh6ch9OQ4gyAARAhqADkKFEG4ANgAylPBAfHy4iORphLgW5AGwAOU4H6aGOF0CBSG4AggDFLgAbAIpPmInEApiLUdIBOQBuALmAwjBgYAAASyROWwOfit0AAAAASUVORK5CYII=',
                        close: 'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAABYSURBVDhPY/wPBAwUACYoTTZAccGTI8VQFiqQsemFsjAB3ACQZhlLN7AgOnhyfBdOQ4gyAARAhqADkKFEG4ANgAylOBBHDRgMBhCVlHEBlIRELqDQCwwMAHrpMxmKmvRfAAAAAElFTkSuQmCC',
                        leaf: 'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAABfSURBVDhPY/wPBAwUACYoTTZAcUHHqrtQFiqoCFOGsrAAkAEw0L7yDpSFCnCJgwBBL4BcBXIBLtcR5QIYwCZPlAtgNDaXEDQAFoC4ApLiaBw1gMikjA6QY2SgcyMDAwC9IJ/Uo4UIgAAAAABJRU5ErkJggg=='
                    }
                },
                selectCallback: null,        //选中行事件的回调方法
                deleteItemCallback: null,    //点击删除当前节点事件的回调方法
                addChildCallback: null,      //点击添加子节点事件的回调方法
                lineHeight: 24,              //行高
                overLineBGColor: "#daecfd",  //鼠标滑过行背景色
                selectLineBGColor: "#ace",   //选中行背景色
                overLineTextColor: "#000",   //鼠标滑过文字颜色
                selectLineTextColor: "#000"  //选中文字颜色
            },          //默认配置
            baseStyle      = function (c) {
                if ($('#ue_tree_style').length < 1) {
                    var f = c.flags[c.flagType];
                    $('head').append(
                          '<style id="ue_tree_style">'
                        + '    .ue_tree_container {position:relative;padding:10px;}'
                        + '    .ue_tree_frame {position:relative;width:100%;border:none;background-color:#fff;font-size:12px;margin:0;height:auto;clear:both;display:inline-block;}'
                        + '    .ue_tree_item {position:relative;display:flex;}'
                        + '    .ue_tree_flag {width:16px;height:' + c.lineHeight + 'px;line-height:' + c.lineHeight + 'px;font-size:smaller;display:inline-block;}'
                        + '    .ue_tree_chk {display:inline-block;margin-top:7px !important;}'
                        + '    .ue_tree_content {font-size:smaller;cursor:default;flex:1;padding:0px;display:inline-block;}'
                        + '    .ue_tree_img {margin-top:' + f.top + 'px;}'
                        + '    .ue_tree_text {float:left;height:' + c.lineHeight + 'px;line-height:' + c.lineHeight + 'px;cursor:pointer;flex:1;}'
                        + '    .ue_tree_text:hover {background-color:' + c.overLineBGColor + ';}'
                        + '    .ue_tree_btn {width:10px;height:10px;line-height:8px;border:1px solid #bdf;border-radius:3px;color:#39f;}'
                        + '    .ue_tree_del {margin:7px 0 0 5px;float:left;font-size:18px;}'
                        + '    .ue_tree_add {margin-top:7px;float:right; }'
                        + '    .ue_tree_btn:hover {background-color:#bdf;}'
                        + '    .ue_tree_treeItem_select{background:' + c.selectLineBGColor + '}'
                        + '</style>');
                }
            },
            formatData     = function (g, d) {
                if(d.id == 0){
                    for(var i = 0; i < g.data.length; i++){
                        var r = g.data[i];
                        var p = g.data.filter(function (item) {
                            return item.id == r.parentId;
                        });
                        if(!p || p.length < 1){
                            d.children.push(r);
                        }
                    }
                }else{
                    d.children = g.data.filter(function (item) {
                        return item.parentId == d.id;
                    });
                }
                for(var i = 0; i < d.children.length; i++){
                    var r = d.children[i];
                    d.isLeaf = false;
                    r.parentId = d.id;
                    r.depth = d.depth + 1;
                    r.isLeaf = true;
                    r.path = d.id + '_' + r.id;
                    formatData(g, r);
                };
                return d;
            },
            changeState    = function (g, d) {
                var c = g.config,
                    f = c.flags[c.flagType],
                    i = d.attr('idx'),
                    h = d.parent().find('.ue_tree_frame[idx="' + i + '"]');
                if (d.attr('state') == 'open') {
                    if (h.length > 0) {
                        h.hide();
                    }
                    var m = c.flagType == 'addReduce' ? f.close : '<img class="ue_tree_img" alt="" src="' + f.close + '"/>';
                    d.attr('state', 'close').html(m);
                } else {
                    if(d.attr('state') == 'close') {
                        if (h.length > 0) {
                            h.show();
                        } else {
                            var tmp = i.split('_');
                            var id = tmp[tmp.length - 1];
                            var dt = g.getDataById(id);
                            addContent(g, d.parent().find('.ue_tree_content[idx="' + i + '"]'), dt);
                        }
                        var m = c.flagType == 'addReduce' ? f.open : '<img class="ue_tree_img" alt="" src="' + f.open + '"/>';
                        d.attr('state', 'open').html(m);
                    }
                }
            },
            bindEvent      = function (g) {
                var c = g.config;
                var d = $('.ue_tree_container');
                d.on('click', '.ue_tree_text', function () {
                    $(".ue_tree_treeItem_select", parent).removeClass('ue_tree_treeItem_select');
                    $(this).addClass('ue_tree_treeItem_select');
                    g.selectedId = $(this).attr('idx');
                    g.selectedItem = g.getDataById(g.selectedId);
                    c.selectCallback && c.selectCallback(g.selectedId, g.selectedItem, $(this));
                });
                d.on('click','.ue_tree_flag', function () {
                    changeState(g, $(this));
                });
                d.on('click','.ue_tree_del', function () {
                    var id = $(this).attr('idx');
                    var item = g.getDataById(id);
                    if(c.deleteItemCallback && c.deleteItemCallback(id, item, $(this))){      
                        item.status = 'deleted'
                        $('.ue_tree_item[idx="' + id + '"]').remove();
                    }
                });
                d.on('click','.ue_tree_add', function () {
                    var id = $(this).attr('idx');
                    var item = g.getDataById(id);
                    if(c.addChildCallback){
                        var dt = c.addChildCallback(id, item, $(this));
                        g.addChild(item, dt);
                    }
                });
            },
            addContent     = function (g, p, d) {
                var c = g.config;
                if (d.children && d.children.length > 0) {
                    var q = $('<div idx="' + d.id + '" class="ue_tree_frame"></div>').appendTo(p);
                    c.isOpen && q.show();
                    for (var i = 0; i < d.children.length; i++) {
                        var cw = addItem(q, d.children[i], c);
                    }
                }
            },
            addItem        = function (p, d, c) {
                if(d.status == 'deleted'){
                    return false;
                }
                var f = c.flags[c.flagType],
                    t = c.isOpen && d.children && d.children.length > 0,
                    m = $('<div idx="' + d.id + '" class="ue_tree_item"></div>').appendTo(p),
                    flag =  d.isLeaf ? f.leaf : t ? f.open : f.close,
                    html = c.flagType == 'addReduce' ? flag : flag == '' ? '' : '<img class="ue_tree_img" alt="" src="' + flag + '"/>';
                $('<div idx="' + d.id + '" state="' + (d.isLeaf ? 'leaf' : t ? 'open' : 'close') + '" class="ue_tree_flag">' + html + '</div>').appendTo(m);

                if (c.hasCheckbox) {
                    m.append('<input type="checkbox" class="ue_tree_chk" />');
                }

                var n = $('<div idx="' + d.id + '" class="ue_tree_content"></div>').appendTo(m);
                var row = $('<div idx="' + d.id + '" class="ue_tree_text"></div>').appendTo(n);
                n.append(row);
                if (d.img) {
                    $('<div class="ue_tree_img"><img alt="" src="' + d.img + '"/></div>').appendTo(n);
                }
                row.append(d.text);
                if (c.hasCreate) {
                    n.append('<div idx="' + d.id + '" class="ue_tree_btn ue_tree_del">-</div>');
                    n.append('<div idx="' + d.id + '" class="ue_tree_btn ue_tree_add">+</div>');
                }
            };
        //公开属性
        this.container     = $(container);
        this.selectedIdx   = 0;            //选中行索引
        this.selectedItem  = null;         //选中行
        this.root          = null;         //数据集
        this.data          = data;         //数据源
        this.config        = $.extend({}, defaultConfig, config);       //配置信息
        this.getDataById   = function (value) {
            for (var i = 0; i < this.data.length; i++) {
                if (this.data[i].id == value) {
                    return this.data[i];
                }
            }
            return null;
        };
        this.bindData      = function (d, c) {
            this.config = c ? $.extend(defaultConfig, c) : this.config;
            baseStyle(this.config);
            parent.attr('idx', '0').addClass('ue_tree_container').html('').appendTo(this.container);
            this.data = d || this.data;
            this.root = { isLeaf: false, depth: 0, path: '0', id: 0, children:[] };
            formatData(this, this.root);
            addContent(this, parent, this.root);
            bindEvent(this);
        };
        this.addChild      = function(p, dt){            
            var tmp = this.getDataById(dt.id);
            if(tmp){
                alert('添加的数据主键已存在');
                return false;
            }
            dt.parentId = p.id;
            dt.depth = p.depth + 1;
            dt.isLeaf = true;
            dt.path = p.path + '_' + dt.id;
            dt.children = [];
            p.isLeaf = false;
            p.children.push(dt);
            this.data.push(dt);
            var frame = $('.ue_tree_frame[idx="' + p.id + '"]');
            if(frame.length < 1){                            
                frame = $('<div idx="' + p.id + '" class="ue_tree_frame"></div>').appendTo($('.ue_tree_content[idx="' + p.id + '"]'));
                frame.show();                
                var c = this.config, 
                    f = c.flags[c.flagType],
                    html = c.flagType == 'addReduce' ? f.open : '<img class="ue_tree_img" alt="" src="' + f.open + '"/>';
                $('.ue_tree_flag[idx="' + p.id + '"]').append(html).attr('state', 'open');
            }
            addItem(frame, dt, this.config);
        };
        this.bindData();
    };
    $.fn.addTree = function (data, config) {
        return new UETree(this, data, config);
    };
}());


var testData = [
    { id: 1,   parentId: 8,  text: '湖北' },
    { id: 11,  parentId: 1,  text: '武汉' },
    { id: 111, parentId: 11, text: '武昌' },
    { id: 112, parentId: 11, text: '汉口' },
    { id: 113, parentId: 11, text: '汉阳' },
    { id: 113, parentId: 11, text: '洪山' },
    { id: 12,  parentId: 1,  text: '襄樊' },
    { id: 13,  parentId: 1,  text: '宜昌' },
    { id: 14,  parentId: 1,  text: '黄石' },
    { id: 2,   parentId: 8,  text: '北京' },
    { id: 3,   parentId: 9,  text: '广东' },
    { id: 31,  parentId: 3,  text: '广州' },
    { id: 32,  parentId: 3,  text: '深圳' },
    { id: 33,  parentId: 3,  text: '澳门' },
    { id: 4,   parentId: 9,  text: '上海' },
    { id: 5,   parentId: 9,  text: '浙江' },
    { id: 41,  parentId: 5,  text: '杭州' },
    { id: 42,  parentId: 5,  text: '温州' },
    { id: 6,   parentId: 8,  text: '香港' },
    { id: 7,   parentId: 9,  text: '台湾' },
    { id: 71,  parentId: 7,  text: '高雄' },
    { id: 72,  parentId: 7,  text: '台北' }
];

    var config = {
        flagType: 'triangle',
        hasCreate: true,
        selectCallback: function (id, dt, item) { 
            alert('select'); 
            return id; 
        },     //选中行事件的回调方法
        deleteItemCallback: function (id, dt, item) { 
            alert('delete'); 
            return true; 
        }, //点击删除当前节点事件的回调方法
        addChildCallback: function (id, dt, item) { 
            alert('add'); 
            return { id:311, parentId:31, text: '白云'}; 
        },      //点击添加子节点事件的回调方法
        //hasCheckbox: true
    };
    var t1 = $('#testTree').addTree(testData, config);
</script>

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值