zoukankan      html  css  js  c++  java
  • JS Tree

    在需要表示级联、层级的关系中,Tree作为最直观的表达方式常出现在组织架构、权限选择等层级关系中。典型的表现形试类似于:

    一颗树的生成常常包括三个部分:1)数据库设计;2)后台程序;3)前端代码。那么,具体是怎么样的呢?

    一、数据库设计

    数据库设计对于树的表达常会包含这么几个类似意思的字段:

    parent_id、id、name。

    id:用于描述自己;

    parent_id:用于描述自己的上一级;

    name:用于描述自己的名称;

    例如:总办(id=3,parent_id=0,name=总办),客户服务中心(id=10,parent_id=3,name=客户服务中心) ,客户部(id=12,parent_id=10,name=客户部)。由此建立了三级层级关系。

    二、后台程序

    对于一个层级,可能会用于描述部门关系,还可能用于描述菜单关系等等,不同的用途有不同的数据库设计字段。但为了程序的通用性,不可能为一了一个表或功能做单独的前端插件,因此就要在后台为前端插件需要使用到的字段做一个规范(或者在数据库设计中做规范)。在此为“树结构”在后台作这样的规范:

    复制代码
     1     /// <summary>
     2 
     3     /// 层级
     4 
     5     /// </summary>
     6 
     7     public class vmHierarchy
     8 
     9     {
    10 
    11         public int id { get; set; }
    12 
    13         public int pid { get; set; }
    14 
    15         public string name { get; set; }
    16 
    17         public object sub { get; set; }
    18 
    19         public int status { get; set; }
    20 
    21 }
    复制代码

    Pid:用于描述上级关系;

    Sub:用于描述子级关系;

    Status:用于描述自身状态或特殊标识;

    以做部门的层级关系为例:分为两个部分:

    1)  取数据:

    复制代码
            /// <summary>
    
            /// 取部门层级
    
            /// </summary>
    
            /// <returns></returns>
    
            public List<vmHierarchy> GetDepartmentRelation()
    
            {
    
                List<vmHierarchy> vmdrlist = new List<vmHierarchy>();
    
                using (var ctx = DB.ContextForName(DBConnection.DefaultConnection).UseTransaction(true))
    
                {
    
                    List<au_Department> adlist = new List<au_Department>();
    
                    adlist = base.GetModelAll();
    
                    vmdrlist = GetDepartmentRelationSub(1, adlist);
    
                }
    
                return vmdrlist;
    
            }
    复制代码

    2) 定层级:

    复制代码
           /// <summary>
    
            /// 取部门层级-子级
    
            /// </summary>
    
            /// <param name="parentid"></param>
    
            /// <param name="adlist"></param>
    
            /// <returns></returns>
    
            public List<vmHierarchy> GetDepartmentRelationSub(int parentid, List<au_Department> adlist)
    
            {
    
                List<vmHierarchy> vmdrlist = new List<vmHierarchy>();
    
                List<au_Department> modellist = new List<au_Department>();
    
                modellist = adlist.Where(s => s.parent_id == parentid).OrderBy(s => s.sequence).ToList<au_Department>();
    
                foreach (au_Department item in modellist)
    
                {
    
                    vmHierarchy vmmodel = new vmHierarchy();
    
                    vmmodel.id = item.id;
    
                    vmmodel.pid = item.parent_id;
    
                    vmmodel.name = item.name;
    
                    vmmodel.sub = GetDepartmentRelationSub(item.id, adlist);
    
                    vmdrlist.Add(vmmodel);
    
                }
    
                return vmdrlist;
    
            }
    复制代码

    由此在前端可以得到类似这样的关系数据:

     

    三、前端代码

    在与前端代码时,关于树的逻辑关系理清是最为主要的。

    1)  如何生成当前层级关系和期子级关系,每个节点的子节点都不同。

    2)  需要复选框吗?

    3)  需要折叠吗?

    4)  当点击一个节点:

      A:其下还有一串节点,要全部选中/全部不选中?

      B:当前点击中其它子节点都被选中了,再选中这个节点,如何影响上级的选中与不选中?

    总结为:在有复选框的情况下,如何影响它的下级和上级节点关系?

    5)  三个事件:

      A:单击选中复选框事件;

      B:单击取消选中复选框事件;

      C:单击行事件;

    事件顺序?冒泡?必要事件与用户自定义事件?

    有需求的童鞋可以看看下面的jQuery代码:

    jQuery:

    复制代码
    //Tree层级关系 Begin
    ; (function ($, window, document, undefined) {
        var defaults = {
            ajaxurl: '',//ajax取数据的url[data==null时有效]
            data: null,//数据
            erow: null,//点击行时要执行的事件function(){}
            checbox: true,//是否有复选框
            initunfold: true,//初始展开true 初始折叠false
            event: {
                selectedrows: null,//单击行时要执行的事件
                checked: null,//选中了复选框时要执行的事件
                unchecked: null//取消选中复选框时要执行的事件
            },//事件
            exchangebar: false,//是否有全部展开 全部折叠 按钮
            onlyleafcheck: false//是否只有最终子节点才显示checkbox
        };
        $.fn.etree = function (options) {
            var $that = $(this);
            var _ops = $.extend(true, {}, defaults, options);
            var $con = null, _activehtml;
            var _lv = 0;
            //初始化数据
            function initdata() {
                if (_ops.data !== null) {
                    generateTree(_ops.data);
                } else {
                    $.ajax({
                        url: _ops.ajaxurl,
                        dataType: "JSON",
                        success: function (result) {
                            _ops.data = result;
                            generateTree(_ops.data);
                        }
                    });
                }
            };
            function generateTree(_data) {
                console.log(_data);
                $con = $('<div></div>').appendTo($that);
                var $ul = $('<ul class="e-tree-ul"></ul>').appendTo($con);
                generateSub($con, _data, _lv);
                initEvent();
                if (_ops.initunfold == false) {
                    $con.find('.tge-inv').each(function () {
                        $(this).click();
                    })
                }
            };
            function generateSub($e, _data, _lv) {
                for (var i = 0; i < _data.length; i++) {
                    var _tdata = _data[i];
                    var $li = $('<li class="e-tree-li"></li>').appendTo($e);
                    var $p = $('<p class="e-tree-p" lv=' + _lv + '></p>').appendTo($li);
                    var $ti = $('<i class="tge-inv"></i>').appendTo($p);
                    var $tif = $('<i class="tge-invf"></i>').appendTo($p);
                    var $tc = null;
                    if (_ops.checbox == true) {
                        if (_ops.onlyleafcheck == true && _tdata.sub.length == 0) {
                            $tc = $('<i class="sck" tid="' + _tdata.id + '"></i>').appendTo($p);
                        } else if (_ops.onlyleafcheck == false) {
                            $tc = $('<i class="sck" tid="' + _tdata.id + '"></i>').appendTo($p);
                        }
                    }
                    var $ts = $('<span class="e-tree-s"></span>').html(_tdata.name).appendTo($p);
                    if (_tdata.sub.length > 0) {
                        $tif.addClass('tge-invfr');
                        var $ul = $('<ul class="e-tree-ul"></ul>').appendTo($li);
                        generateSub($ul, _tdata.sub, (_lv + 1));
                        $ti.addClass('tge-invd');
                    } else {
                        $tif.addClass('tge-invfd');
                    }
                    if ($tc != null) {
                        if (_tdata.status == 1) {
                            $tc.addClass('ck');//选中
                        } else {
                            $tc.addClass('nock');//未选中
                        }
                    }
                }
            };
            function checksubordinate($e) {
                var $slv = $e.parent('p').next('ul');
                if ($e.hasClass('ck')) {
                    $slv.find('.sck').removeClass('nock').addClass('ck');
                } else if ($e.hasClass('nock')) {
                    $slv.find('.sck').removeClass('ck').addClass('nock');
                }
            };
            function checksuperior($e) {
                var $plv = $e.parent('p').parent('li').parent('ul');
                if ($plv.length > 0) {
                    var $sib = $plv.children('li');
                    var $sumckdcount = $sib.children('p').children('.ck').length;
                    var $scount = $sib.length - $sumckdcount;
                    var $ppsck = $plv.prev('p').children('.sck');
                    if ($scount == 0) {
                        $plv.prev('p').children('.sck').removeClass('nock').addClass('ck');
                    } else {
                        $plv.prev('p').children('.sck').removeClass('ck').addClass('nock');
                    }
                    if ($ppsck.length > 0) {
                        checksuperior($ppsck);
                    }
                }
            };
            function checkselect($e) {
                checksuperior($e);
                checksubordinate($e);
            };
            function setAction($e) {
                var $ts = $e;
                var $te = $ts.parent('p');
                var $thisid = parseInt($e.attr('tid'));
                $con.find('.e-tree-active').removeClass('e-tree-active');
                if ($ts.hasClass('ck')) {
                    $ts.removeClass('ck').addClass('nock');
                    checkselect($ts);
                    if (typeof _ops.event.unchecked == "function") {
                        _ops.event.unchecked($te, iselectedhtml());//活动项,唯一选中项|null
                    }
                } else if ($ts.hasClass('nock')) {
                    $ts.removeClass('nock').addClass('ck');
                    checkselect($ts);
                    if (_ops.event.checked != null) {
                        _ops.event.checked($te, iselectedhtml());//活动项,唯一选中项|null
                    }
                }
                var $shtml = iselectedhtml();
                if ($shtml != null) {
                    var $ck = $shtml.children('.ck');
                    var $sid = parseInt($shtml.attr('tid'));
                    $ck.parent('p').addClass('e-tree-active');
                    if ($thisid == $sid) {
                        setAction($ck);
                    }
                }
            };
            function initEvent() {
                $con.find('.tge-inv').bind('click', function (e) {
                    var $ts = $(this);
                    var $next = $ts.parent('p').next();
                    var $tsnext = $ts.next();
                    if ($ts.hasClass('tge-invd')) {
                        $ts.removeClass('tge-invd').addClass('tge-invr');
                        $next.slideUp();
                        if ($tsnext.hasClass('tge-invfr')) {
                            $tsnext.removeClass('tge-invfr').addClass('tge-invfd');
                        }
                    } else if ($ts.hasClass('tge-invr')) {
                        $ts.removeClass('tge-invr').addClass('tge-invd');
                        $next.slideDown();
                        if ($tsnext.hasClass('tge-invfd')) {
                            $tsnext.removeClass('tge-invfd').addClass('tge-invfr');
                        }
                    }
                    e.stopPropagation();
                });
                $con.find('.sck').bind('click', function (e) {
                    var $ts = $(this);
                    setAction($ts);
                    e.stopPropagation();
                });
                $con.find('.e-tree-p').bind('click', function () {
                    $(this).children('.sck').click();
                });
                if (typeof _ops.event.selectedrows == "function") {
                    $con.find('.e-tree-p').bind('click', function () {
                        var $te = $(this).context;
                        _ops.event.selectedrows($($te), iselectedhtml());//活动项,唯一选中项|null
                    });
                }
                $con.find('.e-tree-s').bind('click', function () {
                    return false;
                });
            };
            function iactivehtml() {
                _activehtml = $con.find('.e-tree-active').html();
                return _activehtml;
            };
            function iactiveid() {
                var $thtml = $con.find('.e-tree-active');
                _activeid = parseInt($thtml.find('.sck').attr('tid'));
                return _activeid;
            };
            function iselectedids() {
                var _ids = new Array();
                $con.find('.ck').each(function () {
                    _ids.push(parseInt($(this).attr('tid')));
                });
                return _ids;
            };
            function iselectedhtml() {
                if (iselectedids().length == 1) {
                    return $con.find('.ck').parent('p');
                } else {
                    return null;
                }
            };
            function iselectedid() {
                if (iselectedids().length == 1) {
                    return parseInt($con.find('.ck').attr('tid'));
                } else {
                    return null;
                }
            };
            initdata();
            //活动项html [活动项:当前点击的项]
            this.activehtml = function () {
                return iactivehtml();
            };
            //活动项id [活动项:当前点击的项]
            this.activeid = function () {
                return iactiveid();
            };
            //获取所有选中的项id
            this.selectedids = function () {
                return iselectedids();
            };
            //当前唯一选中项的html 不满足唯一选中时,返回null
            this.selectedhtml = function () {
                return iselectedhtml();
            };
            //当前唯一选中项的id 不满足唯一选中时,返回null
            this.selectedid = function () {
                return iselectedid();
            };
            return this;
        };
    })(jQuery, window, document);
    //Tree层级关系 End
    复制代码

    使用:

    复制代码
    @{
        Layout = null;
    }
    @using UCMS_Commons;
    @using UCMS_Model;
    @using UCMS_Model.ViewModel;
    
    <!DOCTYPE html>
    
    <html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>DepatmentManage</title>
        <link href="~/Content/themes/black/Css/eui.css" rel="stylesheet" />
        <script src="~/Scripts/jquery-1.8.2.min.js"></script>
        <script src="~/Scripts/extendjs/jquery.cookie.js"></script>
        <script src="~/Content/themes/black/Script/jquery.eui.js"></script>
        <style type="text/css">
            #dp-content {
                 920px;
                margin: 0 auto;
            }
    
            #de-cont {
                 400px;
                border: 1px solid #E4E4E4;
                padding: 20px;
                display: inline-block;
                vertical-align: top;
            }
    
            #oper-cont {
                 400px;
                border: 1px solid #E4E4E4;
                padding: 20px;
                display: inline-block;
                vertical-align: top;
                margin-left: 28px;
            }
    
            fieldset {
                border: 1px solid #ddd;
            }
    
            legend {
                color: #9b9b9b;
            }
        </style>
        <script type="text/javascript">
            $(function () {
                var actionUrl = {
                    'GetDpInfo': '/SystemCenter/GetDpInfo',
                    'adddp': '/SystemCenter/AddDp',
                    'deletedp': '/SystemCenter/DeleteDp',
                    'updatedp': '/SystemCenter/UpdateDp'
                };
    
                var t = JSON.parse('@Html.Raw(JSONNet.Serialize(Model))');
                var $opername = $('#oper-name');
                var $opersub = $('#oper-cont-sub');
                var $operinfoo = $('#oper-info-o');
                var $operinfoname = $('#oper-info-name');
                var $errormsg = $('#error-msg');
                var $deletedp = $('#deletedp');
                var $dpname = $('#dpname');
                var _status = -1, _ttname = '';
    
                $('input[name="opertype"]').bind('click', function () {
                    var _index = parseInt($(this).attr('tp'));
                    $operinfoo.show();
                    switch (_index) {
                        case 0: { $opername.attr('readonly', 'readonly'); $opersub.show(); $opername.val(_ttname); $('#oper-info-o').show(); }; break;
                        case 1: { $opername.removeAttr('readonly'); $opersub.hide(); $opername.focus().val(''); _status = 1; }; break;
                        case 2: { $opername.removeAttr('readonly'); $opersub.hide(); $opername.focus().val(''); _status = 2; }; break;
                        case 3: { $opername.removeAttr('readonly'); $opersub.hide(); $opername.focus(); _status = 3; }; break;
                    }
                });
                $('#savedp').bind('click', function () {
                    switch (_status) {
                        case 1: { adddp(1); }; break;
                        case 2: { adddp(2); }; break;
                        case 3: { updatedp(); }; break;
                    }
                });
                $('#deletedp').bind('click', function () {
                    deletedp();
                });
                function adddp(_type) {
                    var _id = _dptree.activeid();
                    var _dpname = $opername.val();
                    if (_dpname.length == 0) {
                        $errormsg.html('请填写 名称');
                    }
                    else {
                        $.ajax({
                            url: actionUrl.adddp,
                            data: { "thisid": _id, "addtype": _type == 1 ? 0 : 1, "addname": _dpname },
                            success: function (result) {
                                var _result = $.eui.checkresult(result);
                                if (_result) {
                                    window.location.reload();
                                }
                            }
                        });
                    }
                };
                function deletedp() {
                    var _ids = _dptree.selectedids();
                    var _idarray = JSON.stringify(_ids);
                    $.ajax({
                        url: actionUrl.deletedp,
                        data: { "ids": _idarray },
                        success: function (result) {
                            var _result = $.eui.checkresult(result);
                            if (_result) {
                                window.location.reload();
                            }
                        }
                    });
                };
                function updatedp() {
                    var _id = _dptree.activeid();
                    var _name = $opername.val();
                    if (_name.length == 0) {
                        $errormsg.html('请填写 名称');
                    }
                    else {
                        $.ajax({
                            url: actionUrl.updatedp,
                            data: { "thisid": _id, "newname": _name },
                            success: function (result) {
                                var _result = $.eui.checkresult(result);
                                if (_result) {
                                    window.location.reload();
                                }
                            }
                        });
                    }
                };
                function getdpinfo(_id) {
                    $.ajax({
                        url: actionUrl.GetDpInfo,
                        data: { "id": _id },
                        success: function (result) {
                            var $os = $('#oper-sub').html('');
                            for (var i = 0; i < result.length; i++) {
                                $('<span style="padding: 0 10px;"></span>').html(result[i].name + '(' + result[i].percount + '人)').appendTo($os);
                            }
                        }
                    });
                };
                function schecked(el, sl) {
                    $('input[name="opertype"]').eq(0).click();
                    if (sl != null) {
    
                        var _name = sl.find('.e-tree-s').html();
                        $dpname.html(_name);
                        $opername.val(_name);
                        _ttname = _name;
                        getdpinfo(_dptree.selectedid());
                        $operinfoo.show();
                    } else {
                        $dpname.html('已选中个数:' + _dptree.selectedids().length);
                        $operinfoo.hide();
                    }
                };
                var _dptree = $('#de-cont-d').etree({
                    data: t,
                    checbox: true,
                    onlyleafcheck: true,
                    event: {
                        selectedrows: function (el, sl) {
    
                        },
                        checked: function (el, sl) {
                            var _tname = el.find('.e-tree-s').html();
                            $deletedp.show();
                            $errormsg.html('');
                            schecked(el, sl);
                        },
                        unchecked: function (el, sl) {
                            $operinfoo.hide();
                            schecked(el, sl);
                        }
                    }
                });
            });
        </script>
    </head>
    <body>
        <div id="dp-content">
            <fieldset id="de-cont">
                <legend>部门</legend>
                <div id="de-cont-d">
    
                </div>
            </fieldset>
            <fieldset id="oper-cont">
                <legend>信息</legend>
                <div id="oper-info-name" style="line-height: 32px;">
                    名称:<span id="dpname"></span>
                    <a href="javascript:void(0);" class="eui-btns" style="float:right;display:none;" id="deletedp">删除?</a>
                </div>
                <div id="oper-info-o" style="display:none;">
                    <hr class="hrgrey" />
                    <p id="oper-cont-d" class="eui-p50">
                        操作类别:
                        <label><input name="opertype" type="radio" value="" tp="0" checked="checked" />查看信息</label>
                        <label><input name="opertype" type="radio" value="" tp="1" />添加同级</label>
                        <label><input name="opertype" type="radio" value="" tp="2" />添加子级</label>
                        <label><input name="opertype" type="radio" value="" tp="3" />修改自身</label>
                    </p>
                    <p class="eui-p50">
                        名称:
                        <input type="text" name="name" value="" id="oper-name" class="eui-input" readonly="readonly" />
                    </p>
                    <p class="eui-p50" id="oper-cont-sub">
                        下辖职位:<span id="oper-sub"></span>
                    </p>
                    <label id="error-msg" class="error-msg"></label>
                    <a href="javascript:void(0);" class="eui-btns" style="float:right;bottom:0;" id="savedp">保存</a>
                </div>
            </fieldset>
        </div>
    </body>
    </html>
    复制代码
     
  • 相关阅读:
    ZOJ 3705 Applications
    UVA 220 Othello
    HDU 2084 数塔
    第五章:变量
    第四章:注释
    第三章:程序结构
    第二章:项目的创建和环境熟悉
    第一章:c#开发环境安装
    处理字段串
    查询表的列信息
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4475467.html
Copyright © 2011-2022 走看看