基于MVC+EasyUI的Web開發(fā)框架經(jīng)驗總結(jié)(2)- 使用EasyUI的樹控件構(gòu)建Web界面

最近花了不少時間在重構(gòu)和進一步提煉我的Web開發(fā)框架上牧抽,力求在用戶體驗和界面設(shè)計方面,和Winform開發(fā)框架保持一致,而在Web上,我主要采用EasyUI的前端界面處理技術(shù),走MVC的技術(shù)路線箭券,在重構(gòu)完善過程中,很多細(xì)節(jié)花費不少時間進行研究和提煉,一步步走過來缠导,也0積累了不少經(jīng)驗,本系列將主要介紹我在進一步完善我的Web框架基礎(chǔ)上積累的經(jīng)驗進行分享溉痢,本隨筆主要介紹使用EasyUI的樹控件構(gòu)建Web界面的相關(guān)經(jīng)驗僻造。
在很多界面設(shè)計上,我們可能都需要引入樹列表控件孩饼,這個控件可以用zTree來實現(xiàn)髓削,也可以用EasyUI的內(nèi)置樹控件進行展示,由于歷史原因镀娶,我原來傾向于使用zTree立膛,最新把它全部修改為EasyUI的樹控件,并進行了完善優(yōu)化梯码,發(fā)現(xiàn)代碼更加簡潔明快旧巾,非常不錯。

1忍些、在界面上使用EasyUI的樹控件

一般情況下鲁猩,使用EasyUI的樹控件,代碼很簡單罢坝,腳本代碼如下所示廓握,主要就是通過調(diào)用url來獲得Json數(shù)據(jù),然后就可以顯示了嘁酿,通過onClick就可以響應(yīng)用戶單擊節(jié)點的操作隙券,每個節(jié)點有id, text, iconCls, checked,state,children等屬性。
1)樹控件的Json數(shù)據(jù)綁定

$('#treeDept').tree({
    url: '/User/GetMyDeptTreeJson?userId=@Session["UserId"]',
    onClick: function (node) {
        loadData(node.id);
    }
});

2)樹控件的折疊和展開
樹控件的展開和折疊闹司,可以通過定義兩個通用的腳本進行處理娱仔,如下所示。

function expandAll(treeName) {
    var node = $('#' + treeName).tree('getSelected');
    if (node) {
        $('#' + treeName).tree('expandAll', node.target);
    }
    else {
        $('#' + treeName).tree('expandAll');
    }
}
function collapseAll(treeName) {
    var node = $('#' + treeName).tree('getSelected');
    if (node) {
        $('#' + treeName).tree('collapseAll', node.target);
    }
    else {
        $('#' + treeName).tree('collapseAll');
    }
}

然后游桩,在頁面加載完畢后牲迫,綁定指定的按鈕控件就可以了嗎,如下代碼所示借卧。

//初始化對象
$(document).ready(function () {
    //初始化機構(gòu)分類
    initOUCategorys();

    //機構(gòu)基礎(chǔ)信息
    initDeptTreeview();
    $("#deptExpand").bind("click", function () {
        expandAll("treeDept");
    });
    $("#deptCollapse").bind("click", function () {
        collapseAll("treeDept");
    });                       

    $("#loading").center(); //loading的圖片顯示居中
});

3)樹控件的復(fù)選框顯示

樹控件默認(rèn)是沒有復(fù)選框的盹憎,它可以通過屬性checkbox設(shè)置讓它進行展示的,如下代碼是我項目里面的代碼铐刘。

其中cascadeCheck是否讓樹控件級聯(lián)的陪每,默認(rèn)是級聯(lián),也就是只要父控件被選中,所有其子控件都會被選中檩禾,我們可以設(shè)置它為false挂签,讓它不級聯(lián),這樣在很多情況下是需要的盼产。

$('#treeFunctionView').tree({
    checkbox: true,
    cascadeCheck: false,
    url: '/Function/GetRoleFunctionByUser?userId=@Session["UserId"]',
    onClick: function (node) {
        //
    }
});

4)樹控件的全選和全不選擇

這個全部不選的特性竹握,我找了很多文章,都沒有找到辆飘,其實后來才發(fā)現(xiàn)啦辐,我們對樹的節(jié)點理解有偏差,認(rèn)識到后蜈项,實現(xiàn)起來也很容易芹关。

如取消全部節(jié)點的選中狀態(tài),代碼如下所示紧卒。它的方法getChecked是返回所有的節(jié)點侥衬,而不是一個節(jié)點。它們把全部選中的節(jié)點放到一個結(jié)合里面跑芳,不像Winform里面轴总,樹節(jié)點需要遞歸查詢,這里只需要一個for循環(huán)就可以展開了博个,我這里把所有勾選的節(jié)點怀樟,設(shè)置為非勾選狀態(tài)就可以實現(xiàn)取消全部樹節(jié)點勾選狀態(tài)了。

function unCheckTree(tree) {
    var nodes = $('#' + tree).tree('getChecked');
    if (nodes) {
        for (var i = 0; i < nodes.length; i++) {
            $('#' + tree).tree('uncheck', nodes[i].target);
        }
    }
}

我們知道盆佣,很多樹控件往堡,為了方便操作,都提供了一個全選或者全部不選的操作共耍,這個在EasyUI的樹控件里面虑灰,也是很容易實現(xiàn)的。這里的getChildren和上面的意思類似痹兜,也是返回所有的子節(jié)點穆咐,不需要在進行遞歸,用一個for循環(huán)就可以遍歷全部節(jié)點和其下面的多級子節(jié)點了字旭。也就是說对湃,它是一個二維的數(shù)據(jù),不用遞歸查詢谐算。

function checkAllTree(tree, checked) {
    var children = $('#' + tree).tree('getChildren');
    for (var i = 0; i < children.length; i++) {
        if (checked) {
            $('#' + tree).tree('check', children[i].target);
        } else {
            $('#' + tree).tree('uncheck', children[i].target);
        }
    }
}

5)下拉列表的樹控件初始化
除了普通的樹列表熟尉,還有一種比較特殊的樹控件归露,就是在ComboTree,也就是在下拉列表中集成樹控件洲脂,它的操作和普通的樹控件差不多,很多事件屬性都一樣,它的使用代碼如下所示恐锦。

//初始化公司
function initCompany() {
    $('#txtCompany_ID').combotree({
        url: '/User/GetMyCompanyTreeJson?userId=@Session["UserId"]',
        valueField: 'id',
        textField: 'text',
        required: true,
        onClick: function (node) {
            //
        }
    });
}

2往果、樹控件的優(yōu)化

1)普通的Json數(shù)據(jù)生成
前面說了,我們?yōu)榱朔奖阋磺Γ话闶褂肑son數(shù)據(jù)和javascript打交道陕贮,而EasyUI的樹控件支持很好地的Json鏈接綁定,因此我們只需要在對應(yīng)的控制器里面實現(xiàn)json數(shù)據(jù)的生成即可潘飘,如果是一開始想要確定的Json數(shù)據(jù)肮之,一般也是通過手工生成的居多,如下代碼所示卜录。

public ActionResult GetTreeJson()
{
    string folder = "/Content/JqueryEasyUI/themes/icons/customed/" + "organ.png";
    string leaf = "/Content/JqueryEasyUI/themes/icons/customed/" + "organ.png";
    string json = GetTreeJson(-1, folder, leaf);
    json = json.Trim(',');
    return Content(string.Format("[{0}]", json));
}

/// <summary>
/// 遞歸獲取樹形信息
/// </summary>
/// <param name="PID"></param>
/// <returns></returns>
private string GetTreeJson(int PID, string folderIcon, string leafIcon)
{
    string condition = string.Format("PID={0}", PID);
    List<OUInfo> nodeList = BLLFactory<OU>.Instance.Find(condition);
    StringBuilder content = new StringBuilder();
    foreach (OUInfo model in nodeList)
    {
        int ParentID = (model.PID == -1 ? 0 : model.PID);
        //string tempMenu = string.Format("{{ id:{0}, pId:{1}, name:\"{2}\",icon:\"{3}\" }},", model.ID, ParentID, model.Name, imgsrc);
        string subMenu = this.GetTreeJson(model.ID, folderIcon, leafIcon);
        string parentMenu = string.Format("{{ \"id\":{0}, \"pId\":{1}, \"name\":\"{2}\" ", model.ID, ParentID, model.Name);
        if (string.IsNullOrEmpty(subMenu))
        {
            if (!string.IsNullOrEmpty(leafIcon))
            {
                parentMenu += string.Format(",\"icon\":\"{0}\" }},", leafIcon);
            }
            else
            {
                parentMenu += "},";
            }
        }
        else
        {
            if (!string.IsNullOrEmpty(folderIcon))
            {
                parentMenu += string.Format(",\"icon\":\"{0}\" }},", folderIcon);
            }
            else
            {
                parentMenu += "},";
            }
        }

        content.AppendLine(parentMenu.Trim());
        content.AppendLine(subMenu.Trim());
    }

    return content.ToString().Trim();
} 

上面的代碼很好實現(xiàn)了根據(jù)數(shù)據(jù)庫結(jié)構(gòu)的關(guān)系戈擒,生成Json數(shù)據(jù),但是感覺部分硬編碼艰毒,湊出來的數(shù)據(jù)筐高,始終感覺不太理想,如果我們要簡化丑瞧,該如何操作呢柑土?

2)簡潔美觀的Json數(shù)據(jù)生成

本小節(jié)繼續(xù)上面的議題,看如何簡化json的生成绊汹,因為我們需要很多這樣的json操作稽屏,如果采用上面的方法,我感覺很容易出錯西乖,而且也不太美觀诫欠。為了解決這個問題,我們可以通過定義一個json數(shù)據(jù)的實體類浴栽,用來承載相關(guān)的信息荒叼,如下定義所示。

/// <summary>
/// 定義EasyUI樹的相關(guān)數(shù)據(jù)典鸡,方便控制器生成Json數(shù)據(jù)進行傳遞
/// </summary>
[DataContract]
[Serializable]
public class EasyTreeData
{
    /// <summary>
    /// ID
    /// </summary>
    [DataMember]
    public string id { get; set; }

    /// <summary>
    /// 節(jié)點名稱
    /// </summary>
    [DataMember]
    public string text { get; set; }
    
    /// <summary>
    /// 是否展開
    /// </summary>
    [DataMember]
    public string state  { get; set; }

    /// <summary>
    /// 圖標(biāo)樣式
    /// </summary>
    [DataMember]
    public string iconCls { get; set; }


    /// <summary>
    /// 子節(jié)點集合
    /// </summary>
    [DataMember]
    public List<EasyTreeData> children { get; set; }
    
    /// <summary>
    /// 默認(rèn)構(gòu)造函數(shù)
    /// </summary>
    public EasyTreeData() 
    {
        this.children = new List<EasyTreeData>();
        this.state = "open";
    }

    /// <summary>
    /// 常用構(gòu)造函數(shù)
    /// </summary>
    public EasyTreeData(string id, string text, string iconCls = "", string state = "open")
        : this()
    {
        this.id = id;
        this.text = text;
        this.state = state;
        this.iconCls = iconCls;
    }

    /// <summary>
    /// 常用構(gòu)造函數(shù)
    /// </summary>
    public EasyTreeData(int id, string text, string iconCls = "", string state = "open")
        : this()
    {
        this.id = id.ToString();
        this.text = text;
        this.state = state;
        this.iconCls = iconCls;
    }
}

然后被廓,我們在需要生成Json數(shù)據(jù)的地方,使用這個實體類進行承載萝玷,然后把它列表生成Json就可以了嫁乘,很簡單了,呵呵球碉。

/// <summary>
/// 根據(jù)用戶獲取對應(yīng)人員層次的樹Json
/// </summary>
/// <param name="deptId">用戶所在部門</param>
/// <returns></returns>
public ActionResult GetUserTreeJson(int deptId)
{
    List<EasyTreeData> treeList = new List<EasyTreeData>();
    treeList.Insert(0, new EasyTreeData(-1, "無"));

    List<UserInfo> list = BLLFactory<User>.Instance.FindByDept(deptId);
    foreach (UserInfo info in list)
    {
        treeList.Add(new EasyTreeData(info.ID, info.FullName, "icon-user"));
    }

    string json = ToJson(treeList);
    return Content(json);
}

如果需要遞歸的操作蜓斧,一樣的方式處理就可以了。

/// <summary>
/// 獲取用戶的部門樹結(jié)構(gòu)(分級需要)
/// </summary>
/// <param name="userId">用戶ID</param>
/// <returns></returns>
public ActionResult GetMyDeptTreeJson(int userId)
{
    StringBuilder content = new StringBuilder();
    UserInfo userInfo = BLLFactory<User>.Instance.FindByID(userId);
    if (userInfo != null)
    {
        OUInfo groupInfo = GetMyTopGroup(userInfo);
        if (groupInfo != null)
        {
            List<OUNodeInfo> list = BLLFactory<OU>.Instance.GetTreeByID(groupInfo.ID);

            EasyTreeData treeData = new EasyTreeData(groupInfo.ID, groupInfo.Name, GetIconcls(groupInfo.Category));
            GetTreeDataWithOUNode(list, treeData);

            content.Append(base.ToJson(treeData));
        }
    }
    string json = string.Format("[{0}]", content.ToString().Trim(','));
    return Content(json);
}

上面使用EasyTreeData來承載數(shù)據(jù)睁冬,然后構(gòu)建列表挎春,其本身就是一個多層級的樹對象看疙,然后一個ToJson的方法就可以把列表對象完美轉(zhuǎn)換為Jason數(shù)據(jù)了。

這里的ToJson直奋,主要就是調(diào)用JavaScriptSerializer 對象進行的操作能庆,如下所示。

/// <summary>
/// 把對象為json字符串
/// </summary>
/// <param name="obj">待序列號對象</param>
/// <returns></returns>
protected string ToJson(object obj)
{
    string jsonData = (new JavaScriptSerializer()).Serialize(obj);
    return jsonData;
}

3脚线、樹控件效果展示

在介紹如何使用它之后搁胆,我們來看看我?guī)讉€場景中使用樹控件進行的展示效果,方便我們加深上面EasyUI樹控件使用的了解邮绿。
1)組織機構(gòu)列表如下所示:



2)角色樹列表展示


3)功能樹列表展示



4)菜單樹列表展示



5)登陸日志樹列表展示

6)下拉列表樹展示



最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末渠旁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子船逮,更是在濱河造成了極大的恐慌一死,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件傻唾,死亡現(xiàn)場離奇詭異投慈,居然都是意外死亡,警方通過查閱死者的電腦和手機冠骄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門伪煤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凛辣,你說我怎么就攤上這事抱既。” “怎么了扁誓?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵防泵,是天一觀的道長。 經(jīng)常有香客問我蝗敢,道長捷泞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任寿谴,我火速辦了婚禮锁右,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘讶泰。我一直安慰自己咏瑟,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布痪署。 她就那樣靜靜地躺著码泞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狼犯。 梳的紋絲不亂的頭發(fā)上余寥,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天领铐,我揣著相機與錄音,去河邊找鬼劈狐。 笑死罐孝,一個胖子當(dāng)著我的面吹牛呐馆,可吹牛的內(nèi)容都是我干的肥缔。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼汹来,長吁一口氣:“原來是場噩夢啊……” “哼续膳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起收班,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤坟岔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后摔桦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體社付,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年邻耕,在試婚紗的時候發(fā)現(xiàn)自己被綠了鸥咖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡兄世,死狀恐怖啼辣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情御滩,我是刑警寧澤鸥拧,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站削解,受9級特大地震影響富弦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜氛驮,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一舆声、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柳爽,春花似錦媳握、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赵誓,卻和暖如春打毛,著一層夾襖步出監(jiān)牢的瞬間柿赊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工幻枉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碰声,地道東北人。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓熬甫,卻偏偏與公主長得像胰挑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子椿肩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容