fuelux tree简单配置使用(动态数据+字体图标)

目录

 fuelux tree配置项(动态数据+字体图标)

fuelux tree 的HTML:

配置 非无穷树(实际开发中):

配置 循环树(官网API):

Fuel UX Tree 树的js (动过手脚使其能自定义图标)

配置 树的 样式


 fuelux tree配置项(动态数据+字体图标)

在web项目开发中,我们不免会遇到各种树的信息展示,我也遇到同样的 问题,不过目前的前端树展示千奇百怪,其中 `ztree(功能最强,样式騒丑)` 还有`bootstrap 的 Treeview也不错`,今天,讲的是 ` fuelux tree` 中的 树 插件,这个插件的好处 就是树的节点图标可自定义(需要改代码,后面会展示),什么`bootstrap 的glyphicon字体`、`font-awesome的 fa 字体`,话不多说,直接上代码

 fuelux tree 的HTML:

配置 非无穷树(实际开发中):

$(function() {
    var treeDataSource = new StaticTreeDataSource(folders);

    $('#MyTree').tree({
        dataSource: treeDataSource.getData,
        multiSelect: false,     //能否多选节点
        folderSelect: false,    //根节点能否选中
        //注:配置 节点  首先 必须HTML 中的图标和 自定义的图标统一
        //否则 不统一可能 节点 能展开 但图标没有切换 或者 不能展开
        iconFolderOpen: "glyphicon-minus-sign",     //节点展开图标
        iconFolderClose: "glyphicon-plus-sign"      //节点关闭图标
    });
})

//初始化树的信息
function StaticTreeDataSource(treeData) {
    var nodes = treeData;

    this.getData = function(options, callback) {
        console.log(JSON.stringify(options))
        //数据第一次初始化时 此时的 options 没有信息
        if($.isEmptyObject(options)) {
            nodes = nodes;
        } else {
            //获取当前点击节点的 options
            if(options.children == null || options.children == undefined) {
                nodes = {};
            } else {
                nodes = options.children;
            }
        }
        //方法回调  添加当前选中节点的子节点
        callback({
            data: nodes
        });
    }
}

var folders = [{
        "name": "Aquire",
        "type": "item"
    },
    {
        "name": "Onboard",
        "type": "item"
    },
    {
        "name": "Engage",
        "type": "folder",
        "attr": {
            "id": "Engage",
            "data-icon": "glyphicon glyphicon-folder-open",
            "style": "color: rebeccapurple;"
        },
        "children": [{
                "name": "Abandoned Cart",
                "type": "folder",
                "children": [{
                    "name": "Archive",
                    "type": "item"
                }]
            },
            {
                "name": "Birthday",
                "type": "item"
            },
            {
                "name": "Browse Retargeting",
                "type": "item"
            },
            {
                "name": "Loyalty",
                "type": "item"
            },
            {
                "name": "Newsletter",
                "type": "item"
            },
            {
                "name": "Post-Purchase",
                "type": "item"
            },
            {
                "name": "Promotional",
                "type": "item"
            },
            {
                "name": "Transactional",
                "type": "folder",
                "children": [{
                    "name": "Archive",
                    "type": "item"
                }]
            },
            {
                "name": "Wish List",
                "type": "item"
            }
        ]
    },
    {
        "name": "Retain",
        "type": "item",
        "attr": {
            "id": "sky-and-water-i",
            "style": "color: rebeccapurple;" //自定义节点颜色
        }
    }
];

配置 循环树(官网API):

function staticDataSource(parentData, callback) {
    childNodesArray = [{
            "name": "Ascending and Descending",
            "type": "folder",
            "attr": {
                "id": "ascending-and-descending"
            }
        },
        {
            "name": "Sky and Water I",
            "type": "item",
            "attr": {
                "id": "sky-and-water-i",
                "data-icon": "glyphicon glyphicon-file",
                "style": "color: rebeccapurple;"
            }
        },
        {
            "name": "Drawing Hands",
            "type": "folder",
            "attr": {
                "id": "drawing-hands"
            }
        },
        {
            "name": "Waterfall",
            "type": "item",
            "attr": {
                "id": "waterfall",
                "data-icon": "glyphicon glyphicon-cloud",
                "style": "color: rebeccapurple;"
            }
        },
        {
            "name": "Belvedere",
            "type": "folder",
            "attr": {
                "id": "belvedere"
            }
        },
        {
            "name": "Relativity",
            "type": "item",
            "attr": {
                "id": "relativity",
                "data-icon": "glyphicon glyphicon-picture",
                "style": "color: rebeccapurple;"
            }
        },
        {
            "name": "House of Stairs",
            "type": "folder",
            "attr": {
                "id": "house-of-stairs"
            }
        },
        {
            "name": "Convex and Concave",
            "type": "item",
            "attr": {
                "id": "convex-and-concave",
                "data-icon": "glyphicon glyphicon-tags",
                "style": "color: rebeccapurple;"
            }
        }
    ];

    callback({
        data: childNodesArray
    });
}

//初始化 树信息
$('#MyTree').tree({
    dataSource: staticDataSource,
    multiSelect: false,
    folderSelect: false,
    iconFolderOpen: "glyphicon-minus-sign",
    iconFolderClose: "glyphicon-plus-sign"
}); 

Fuel UX Tree 树的js (动过手脚使其能自定义图标)

这里用的的是 FuelUX 3.0

 

/*
 * Fuel UX Tree 3.0
 * https://github.com/ExactTarget/fuelux
 *
 * Copyright (c) 2014 ExactTarget
 * Licensed under the BSD New license.
 */

// -- BEGIN UMD WRAPPER PREFACE --

// For more information on UMD visit:
// https://github.com/umdjs/umd/blob/master/jqueryPlugin.js

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // if AMD loader is available, register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // OR use browser globals if AMD is not present
        factory(jQuery);
    }
}(function ($) {
    // -- END UMD WRAPPER PREFACE --

    // -- BEGIN MODULE CODE HERE --

    var old = $.fn.tree;

    // TREE CONSTRUCTOR AND PROTOTYPE

    var Tree = function Tree(element, options) {
        this.$element = $(element);
        this.options = $.extend({}, $.fn.tree.defaults, options);

        if (this.options.itemSelect) {
            this.$element.on('click.fu.tree', '.tree-item', $.proxy(function (ev) {
                this.selectItem(ev.currentTarget);
            }, this));
        }

        this.$element.on('click.fu.tree', '.tree-branch-name', $.proxy(function (ev) {
            this.toggleFolder(ev.currentTarget);
        }, this));

        // folderSelect default is true
        if (this.options.folderSelect) {
            this.$element.addClass('tree-folder-select');
            this.$element.off('click.fu.tree', '.tree-branch-name');
            this.$element.on('click.fu.tree', '.icon-caret', $.proxy(function (ev) {
                this.toggleFolder($(ev.currentTarget).parent());
            }, this));
            this.$element.on('click.fu.tree', '.tree-branch-name', $.proxy(function (ev) {
                this.selectFolder($(ev.currentTarget));
            }, this));
        }

        this.render();
    };

    Tree.prototype = {
        constructor: Tree,

        deselectAll: function deselectAll(nodes) {
            // clear all child tree nodes and style as deselected
            nodes = nodes || this.$element;
            var $selectedElements = $(nodes).find('.tree-selected');
            $selectedElements.each(function (index, element) {
                styleNodeDeselected( $(element), $(element).find( '.glyphicon' ) );
            });
            return $selectedElements;
        },

        destroy: function destroy() {
            // any external bindings [none]
            // empty elements to return to original markup
            this.$element.find("li:not([data-template])").remove();

            this.$element.remove();
            // returns string of markup
            return this.$element[0].outerHTML;
        },

        render: function render() {
            this.populate(this.$element);
        },

        populate: function populate($el, isBackgroundProcess) {
            var self = this;
            var $parent = ($el.hasClass('tree')) ? $el : $el.parent();
            var loader = $parent.find('.tree-loader:eq(0)');
            var treeData = $parent.data();
            isBackgroundProcess = isBackgroundProcess || false; // no user affordance needed (ex.- "loading")

            if (isBackgroundProcess === false) {
                loader.removeClass('hide hidden'); // hide is deprecated
            }
            this.options.dataSource(treeData ? treeData : {}, function (items) {
                loader.addClass('hidden');

                $.each(items.data, function (index, value) {
                    var $entity;

                    if (value.type === 'folder') {
                        $entity = self.$element.find('[data-template=treebranch]:eq(0)').clone().removeClass('hide hidden').removeData('template'); // hide is deprecated
                        $entity.data(value);
                        $entity.find('.tree-branch-name > .tree-label').html(value.text || value.name);
                    } else if (value.type === 'item') {
                        $entity = self.$element.find('[data-template=treeitem]:eq(0)').clone().removeClass('hide hidden').removeData('template'); // hide is deprecated
                        $entity.find('.tree-item-name > .tree-label').html(value.text || value.name);
                        $entity.data(value);
                    }

                    // Decorate $entity with data or other attributes making the
                    // element easily accessable with libraries like jQuery.
                    //
                    // Values are contained within the object returned
                    // for folders and items as attr:
                    //
                    // {
                    //     text: "An Item",
                    //     type: 'item',
                    //     attr = {
                    //         'classes': 'required-item red-text',
                    //         'data-parent': parentId,
                    //         'guid': guid,
                    //         'id': guid
                    //     }
                    // };
                    //
                    // the "name" attribute is also supported but is deprecated for "text".

                    // add attributes to tree-branch or tree-item
                    var attr = value.attr || value.dataAttributes || [];
                    $.each(attr, function (key, value) {
                        switch (key) {
                            case 'cssClass':
                            case 'class':
                            case 'className':
                                $entity.addClass(value);
                                break;

                            // allow custom icons
                            case 'data-icon':
                                $entity.find('.icon-item').removeClass().addClass('icon-item ' + value);
                                $entity.attr(key, value);
                                break;

                            // ARIA support
                            case 'id':
                                $entity.attr(key, value);
                                $entity.attr('aria-labelledby', value + '-label');
                                $entity.find('.tree-branch-name > .tree-label').attr('id', value + '-label');
                                break;

                            // style, data-*
                            default:
                                $entity.attr(key, value);
                                break;
                        }
                    });

                    // add child nodes
                    if ($el.hasClass('tree-branch-header')) {
                        $parent.find('.tree-branch-children:eq(0)').append($entity);
                    } else {
                        $el.append($entity);
                    }
                });

                // return newly populated folder
                self.$element.trigger('loaded.fu.tree', $parent);
            });
        },

        selectTreeNode: function selectItem(clickedElement, nodeType) {
            var clicked = {};   // object for clicked element
            clicked.$element = $(clickedElement);

            var selected = {}; // object for selected elements
            selected.$elements = this.$element.find('.tree-selected');
            selected.dataForEvent = [];

            // determine clicked element and it's icon
            if (nodeType === 'folder') {
                // make the clicked.$element the container branch
                clicked.$element = clicked.$element.closest('.tree-branch');
                clicked.$icon = clicked.$element.find('.icon-folder');
            }
            else {
                clicked.$icon = clicked.$element.find('.icon-item');
            }
            clicked.elementData = clicked.$element.data();

            // the below functions pass objects by copy/reference and use modified object in this function
            if ( this.options.multiSelect ) {
                multiSelectSyncNodes(this, clicked, selected);
            }
            else {
                singleSelectSyncNodes(this, clicked, selected);
            }

            // all done with the DOM, now fire events
            this.$element.trigger(selected.eventType + '.fu.tree', {
                target: clicked.elementData,
                selected: selected.dataForEvent
            });

            clicked.$element.trigger('updated.fu.tree', {
                selected: selected.dataForEvent,
                item: clicked.$element,
                eventType: selected.eventType
            });
        },

        discloseFolder: function discloseFolder(el) {
            var $el = $(el);

            var $branch = $el.closest('.tree-branch');
            var $treeFolderContent = $branch.find('.tree-branch-children');
            var $treeFolderContentFirstChild = $treeFolderContent.eq(0);

            //take care of the styles
            $branch.addClass('tree-open');
            $branch.attr('aria-expanded', 'true');
            $treeFolderContentFirstChild.removeClass('hide hidden'); // hide is deprecated

            //DIY  配置 节点展开图标  首先 必须HTML 中的图标和 自定义的图标统一
            $branch.find('> .tree-branch-header .icon-folder').eq(0)
                .removeClass(this.options.iconFolderClose)
                .addClass(this.options.iconFolderOpen);

            /*//原本的 节点 关闭 切换    
            $branch.find('> .tree-branch-header .icon-folder').eq(0)
                .removeClass('glyphicon-folder-close')
                .addClass('glyphicon-folder-open'); */

            //add the children to the folder
            if (!$treeFolderContent.children().length) {
                this.populate($treeFolderContent);
            }

            this.$element.trigger('disclosedFolder.fu.tree', $branch.data());
        },

        closeFolder: function closeFolder(el) {
            var $el = $(el);
            var $branch = $el.closest('.tree-branch');
            var $treeFolderContent = $branch.find('.tree-branch-children');
            var $treeFolderContentFirstChild = $treeFolderContent.eq(0);

            //take care of the styles
            $branch.removeClass('tree-open');
            $branch.attr('aria-expanded', 'false');
            $treeFolderContentFirstChild.addClass('hidden');


            // DIY 配置 节点 关闭 切换图标
            $branch.find('> .tree-branch-header .icon-folder').eq(0)
                .removeClass(this.options.iconFolderOpen)
                .addClass(this.options.iconFolderClose);

            /*  //原本的 节点关闭切换 
             * $branch.find('> .tree-branch-header .icon-folder').eq(0)
                .removeClass('glyphicon-folder-open')
                .addClass('glyphicon-folder-close');*/

            // remove chidren if no cache
            if (!this.options.cacheItems) {
                $treeFolderContentFirstChild.empty();
            }

            this.$element.trigger('closed.fu.tree', $branch.data());
        },

        toggleFolder: function toggleFolder(el) {
            var $el = $(el);

            /**
             * DIY 修改 判断节点 是否展开
             */
            if ($el.parent(".tree-branch-header").parent(".tree-branch").hasClass("tree-open")) {
                this.closeFolder(el);
            } else{
                this.discloseFolder(el);
            }

            /**  //原本的  节点展开判断
            if ($el.find('.glyphicon-folder-close').length) {
                this.discloseFolder(el);
            } else if ($el.find('.glyphicon-folder-open').length) {
                this.closeFolder(el);
            } */
        },

        selectFolder: function selectFolder(el) {
            if (this.options.folderSelect) {
                this.selectTreeNode(el, 'folder');
            }
        },

        selectItem: function selectItem(el) {
            if (this.options.itemSelect) {
                this.selectTreeNode(el, 'item');
            }
        },

        selectedItems: function selectedItems() {
            var $sel = this.$element.find('.tree-selected');
            var data = [];

            $.each($sel, function (index, value) {
                data.push($(value).data());
            });
            return data;
        },

        // collapses open folders
        collapse: function collapse() {
            var self = this;
            var reportedClosed = [];

            var closedReported = function closedReported(event, closed) {
                reportedClosed.push(closed);

                // hide is deprecated
                if (self.$element.find(".tree-branch.tree-open:not('.hidden, .hide')").length === 0) {
                    self.$element.trigger('closedAll.fu.tree', {
                        tree: self.$element,
                        reportedClosed: reportedClosed
                    });
                    self.$element.off('loaded.fu.tree', self.$element, closedReported);
                }
            };

            //trigger callback when all folders have reported closed
            self.$element.on('closed.fu.tree', closedReported);

            self.$element.find(".tree-branch.tree-open:not('.hidden, .hide')").each(function () {
                self.closeFolder(this);
            });
        },

        //disclose visible will only disclose visible tree folders
        discloseVisible: function discloseVisible() {
            var self = this;

            var $openableFolders = self.$element.find(".tree-branch:not('.tree-open, .hidden, .hide')");
            var reportedOpened = [];

            var openReported = function openReported(event, opened) {
                reportedOpened.push(opened);

                if (reportedOpened.length === $openableFolders.length) {
                    self.$element.trigger('disclosedVisible.fu.tree', {
                        tree: self.$element,
                        reportedOpened: reportedOpened
                    });
                    /*
                    * Unbind the `openReported` event. `discloseAll` may be running and we want to reset this
                    * method for the next iteration.
                    */
                    self.$element.off('loaded.fu.tree', self.$element, openReported);
                }
            };

            //trigger callback when all folders have reported opened
            self.$element.on('loaded.fu.tree', openReported);

            // open all visible folders
            self.$element.find(".tree-branch:not('.tree-open, .hidden, .hide')").each(function triggerOpen() {
                self.discloseFolder($(this).find('.tree-branch-header'));
            });
        },

        /**
        * Disclose all will keep listening for `loaded.fu.tree` and if `$(tree-el).data('ignore-disclosures-limit')`
        * is `true` (defaults to `true`) it will attempt to disclose any new closed folders than were
        * loaded in during the last disclosure.
        */
        discloseAll: function discloseAll() {
            var self = this;

            //first time
            if (typeof self.$element.data('disclosures') === 'undefined') {
                self.$element.data('disclosures', 0);
            }

            var isExceededLimit = (self.options.disclosuresUpperLimit >= 1 && self.$element.data('disclosures') >= self.options.disclosuresUpperLimit);
            var isAllDisclosed = self.$element.find(".tree-branch:not('.tree-open, .hidden, .hide')").length === 0;


            if (!isAllDisclosed) {
                if (isExceededLimit) {
                    self.$element.trigger('exceededDisclosuresLimit.fu.tree', {
                        tree: self.$element,
                        disclosures: self.$element.data('disclosures')
                    });

                    /*
                    * If you've exceeded the limit, the loop will be killed unless you
                    * explicitly ignore the limit and start the loop again:
                    *
                    *    $tree.one('exceededDisclosuresLimit.fu.tree', function () {
                    *        $tree.data('ignore-disclosures-limit', true);
                    *        $tree.tree('discloseAll');
                    *    });
                    */
                    if (!self.$element.data('ignore-disclosures-limit')) {
                        return;
                    }

                }

                self.$element.data('disclosures', self.$element.data('disclosures') + 1);

                /*
                * A new branch that is closed might be loaded in, make sure those get handled too.
                * This attachment needs to occur before calling `discloseVisible` to make sure that
                * if the execution of `discloseVisible` happens _super fast_ (as it does in our QUnit tests
                * this will still be called. However, make sure this only gets called _once_, because
                * otherwise, every single time we go through this loop, _another_ event will be bound
                * and then when the trigger happens, this will fire N times, where N equals the number
                * of recursive `discloseAll` executions (instead of just one)
                */
                self.$element.one('disclosedVisible.fu.tree', function () {
                    self.discloseAll();
                });

                /*
                * If the page is very fast, calling this first will cause `disclosedVisible.fu.tree` to not
                * be bound in time to be called, so, we need to call this last so that the things bound
                * and triggered above can have time to take place before the next execution of the
                * `discloseAll` method.
                */
                self.discloseVisible();
            } else {
                self.$element.trigger('disclosedAll.fu.tree', {
                    tree: self.$element,
                    disclosures: self.$element.data('disclosures')
                });

                //if `cacheItems` is false, and they call closeAll, the data is trashed and therefore
                //disclosures needs to accurately reflect that
                if (!self.options.cacheItems) {
                    self.$element.one('closeAll.fu.tree', function () {
                        self.$element.data('disclosures', 0);
                    });
                }

            }
        },

        // This refreshes the children of a folder. Please destroy and re-initilize for "root level" refresh.
        // The data of the refreshed folder is not updated. This control's architecture only allows updating of children.
        // Folder renames should probably be handled directly on the node.
        refreshFolder: function refreshFolder($el) {
            var $treeFolder = $el.closest('.tree-branch');
            var $treeFolderChildren = $treeFolder.find('.tree-branch-children');
            $treeFolderChildren.eq(0).empty();

            if ($treeFolder.hasClass('tree-open')) {
                this.populate($treeFolderChildren, false);
            }
            else {
                this.populate($treeFolderChildren, true);
            }

            this.$element.trigger('refreshedFolder.fu.tree', $treeFolder.data());
        }

    };

    // ALIASES

    //alias for collapse for consistency. "Collapse" is an ambiguous term (collapse what? All? One specific branch?)
    Tree.prototype.closeAll = Tree.prototype.collapse;
    //alias for backwards compatibility because there's no reason not to.
    Tree.prototype.openFolder = Tree.prototype.discloseFolder;
    //For library consistency
    Tree.prototype.getValue = Tree.prototype.selectedItems;

    // PRIVATE FUNCTIONS

    function styleNodeSelected ($element, $icon) {
        $element.addClass('tree-selected');
        if ( $element.data('type') === 'item' && $icon.hasClass('fueluxicon-bullet') ) {
            $icon.removeClass('fueluxicon-bullet').addClass('glyphicon-ok'); // make checkmark
        }
    }

    function styleNodeDeselected ($element, $icon) {
        $element.removeClass('tree-selected');
        if ( $element.data('type') === 'item' && $icon.hasClass('glyphicon-ok') ) {
            $icon.removeClass('glyphicon-ok').addClass('fueluxicon-bullet'); // make bullet
        }
    }

    function multiSelectSyncNodes (self, clicked, selected) {
        // search for currently selected and add to selected data list if needed
        $.each(selected.$elements, function (index, element) {
            var $element = $(element);
            if ($element[0] !== clicked.$element[0]) {
                selected.dataForEvent.push( $($element).data() );
            }
        });

        if (clicked.$element.hasClass('tree-selected')) {
            styleNodeDeselected (clicked.$element, clicked.$icon);
            // set event data
            selected.eventType = 'deselected';
        }
        else {
            styleNodeSelected(clicked.$element, clicked.$icon);
            // set event data
            selected.eventType = 'selected';
            selected.dataForEvent.push(clicked.elementData);
        }
    }

    function singleSelectSyncNodes(self, clicked, selected) {
        // element is not currently selected
        if (selected.$elements[0] !== clicked.$element[0]) {
            var clearedElements = self.deselectAll(self.$element);
            styleNodeSelected(clicked.$element, clicked.$icon);
            // set event data
            selected.eventType = 'selected';
            selected.dataForEvent = [clicked.elementData];
        }
        else {
            styleNodeDeselected(clicked.$element, clicked.$icon);
            // set event data
            selected.eventType = 'deselected';
            selected.dataForEvent = [];
        }
    }


    // TREE PLUGIN DEFINITION

    $.fn.tree = function tree(option) {
        var args = Array.prototype.slice.call(arguments, 1);
        var methodReturn;

        var $set = this.each(function () {
            var $this = $(this);
            var data = $this.data('fu.tree');
            var options = typeof option === 'object' && option;

            if (!data) {
                $this.data('fu.tree', (data = new Tree(this, options)));
            }

            if (typeof option === 'string') {
                methodReturn = data[option].apply(data, args);
            }
        });

        return (methodReturn === undefined) ? $set : methodReturn;
    };

    $.fn.tree.defaults = {
        dataSource: function dataSource(options, callback) {},
        multiSelect: false,
        cacheItems: true,
        folderSelect: true,
        itemSelect: true,

        // DIY   配置 节点 默认 展开 关闭 图标
        //打开图标
        iconFolderOpen:"glyphicon-minus-sign",
        //关闭图标
        iconFolderClose:"glyphicon-plus-sign",

        /*
        * How many times `discloseAll` should be called before a stopping and firing
        * an `exceededDisclosuresLimit` event. You can force it to continue by
        * listening for this event, setting `ignore-disclosures-limit` to `true` and
        * starting `discloseAll` back up again. This lets you make more decisions
        * about if/when/how/why/how many times `discloseAll` will be started back
        * up after it exceeds the limit.
        *
        *    $tree.one('exceededDisclosuresLimit.fu.tree', function () {
        *        $tree.data('ignore-disclosures-limit', true);
        *        $tree.tree('discloseAll');
        *    });
        *
        * `disclusuresUpperLimit` defaults to `0`, so by default this trigger
        * will never fire. The true hard the upper limit is the browser's
        * ability to load new items (i.e. it will keep loading until the browser
        * falls over and dies). On the Fuel UX `index.html` page, the point at
        * which the page became super slow (enough to seem almost unresponsive)
        * was `4`, meaning 256 folders had been opened, and 1024 were attempting to open.
        */
        disclosuresUpperLimit: 0
    };

    $.fn.tree.Constructor = Tree;

    $.fn.tree.noConflict = function () {
        $.fn.tree = old;
        return this;
    };


    // NO DATA-API DUE TO NEED OF DATA-SOURCE

    // -- BEGIN UMD WRAPPER AFTERWORD --
}));
// -- END UMD WRAPPER AFTERWORD --

配置 树的 样式

.content {
    margin: 0px auto;
    width: 400px;
    height: 400px;
    overflow: auto;
    padding: 10px;
    border: 1px solid #CCCCCC;
}

.tree {
    padding-left: 14px;
    overflow: auto;
    position: relative
}

.tree:before {
    width: 1px;
    z-index: 1;
    display: block;
    content: "";
    position: absolute;
    top: -21px;
    bottom: 16px;
    left: 0;
    border-left: 1px dotted #666
}

.tree.tree-solid-line {
    padding-left: 12px
}

.tree.tree-solid-line:before {
    border-left: 1px solid #999
}

.tree.tree-solid-line .tree-folder .tree-folder-content:before {
    border-left: 1px solid #999
}

.tree.tree-no-line {
    padding-left: 0
}

.tree.tree-no-line:before {
    display: none
}

.tree.tree-no-line .tree-folder .tree-folder-content:before {
    display: none
}

.tree .tree-folder {
    width: auto;
    min-height: 20px;
    cursor: pointer
}

.tree .tree-folder .tree-folder-header {
    position: relative;
    min-height: 20px;
    line-height: 20px;
    min-width: 100px
}

.tree .tree-folder .tree-folder-header:hover {
    background-color: #eee
}

.tree .tree-folder .tree-folder-header .tree-folder-name {
    margin-left: 2px
}

.tree .tree-folder img {
    margin-left: 4px
}

.tree .tree-folder .tree-folder-content {
    margin-left: 23px;
    position: relative
}

.tree .tree-folder .tree-folder-content:before {
    display: inline-block;
    content: "";
    position: absolute;
    width: 1px;
    z-index: 1;
    top: -9px;
    bottom: 16px;
    left: -12px;
    border-left: 1px dotted #666
}

.tree .tree-item {
    position: relative;
    min-height: 20px;
    line-height: 20px;
    min-width: 100px;
    cursor: pointer
}

.tree .tree-item:hover {
    background-color: #eee
}

.tree .tree-item .tree-item-name {
    margin-left: 2px
}

.tree .tree-folder,
.tree .tree-item {
    position: relative
}

.tree .tree-folder:before,
.tree .tree-item:before {
    display: inline-block;
    content: "";
    position: absolute;
    top: 14px;
    left: -13px;
    width: 18px;
    height: 0;
    border-top: 1px dotted #666;
    z-index: 1
}

.tree .tree-selected {
    background-color: #eee;
    color: #262626
}

.tree .tree-selected:hover {
    background-color: #e5e5e5
}

.tree .tree-folder .tree-folder-header .tree-folder-name,
.tree .tree-item .tree-item-name {
    display: inline;
    z-index: 2
}

.tree.tree-solid-line .tree-folder:before,
.tree.tree-solid-line .tree-item:before {
    border-top: 1px solid #999
}

.tree.tree-no-line .tree-folder:before,
.tree.tree-no-line .tree-item:before {
    display: none
}

.tree .tree-item,
.tree .tree-folder {
    border: 1px solid transparent
}

.tree .tree-item,
.tree .tree-folder .tree-folder-header {
    margin: 0;
    padding: 4px 5px 6px 5px;
    color: #333;
    -webkit-box-sizing: content-box;
    -moz-box-sizing: content-box;
    box-sizing: content-box
}

.tree .tree-item .tree-item-name>i,
.tree .tree-folder .tree-folder-header>i {
    color: #666;
    display: inline-block;
    font-family: FontAwesome;
    font-style: normal;
    font-weight: normal;
    line-height: 1;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale
}

.tree .tree-item.tree-selected i,
.tree .tree-item .tree-item-name i {
    margin-left: 2px;
    width: 14px;
    display: inline-block;
    text-align: center;
    margin-right: 1px;
    color: #262626
}

.tree.tree-plus-minus .tree-folder-header .fa-folder-open:before {
    height: 16px;
    width: 16px;
    line-height: 16px;
    vertical-align: middle;
    display: inline-block;
    background-position: 0 -21px;
    content: ""
}

.tree.tree-plus-minus .tree-folder-header .fa-folder:before {
    height: 16px;
    width: 16px;
    line-height: 16px;
    vertical-align: middle;
    display: inline-block;
    background-position: 0 2px;
    content: ""
}

.tree.tree-plus-minus .tree-folder-name {
    margin-left: 0 !important
}

.tree .tree-actions {
    display: none;
    position: absolute;
    margin-top: 1px;
    right: 4px
}

.tree .tree-item:hover .tree-actions,
.tree .tree-folder-header:hover .tree-actions {
    display: inline-block
}

.tree .tree-actions>i {
    font-weight: 300;
    padding: 1px 3px;
    text-align: center;
    font-size: 14px;
    color: #333;
    margin-right: 6px;
    margin-top: 0;
    display: inline-block
}

.tree .tree-actions>i:hover {
    font-weight: bold
}

.tree-loading {
    color: #2dc3e8;
    margin-left: 30px
}

 

你可能感兴趣的:(HTML)