基于MVC+EasyUI的Web開發框架經驗總結(3)- 使用Json實體類構建菜單數據

最近花了不少時間在重構和進一步提煉我的Web開發框架上,力求在用戶體驗和界面設計方面,和Winform開發框架保持一致,而在Web上,我主要采用EasyUI的前端界面處理技術,走MVC的技術路線,在重構完善過程中,很多細節花費不少時間進行研究和提煉,一步步走過來,也積累了不少經驗,本系列將主要介紹我在進一步完善我的Web框架基礎上積累的經驗進行分享,本隨筆主要介紹使用如何使用Json實體類構建菜單數據,然后在主界面中進行使用。
菜單的界面效果如下所示,菜單分為一級菜單、二級菜單、三級菜單,他們各自在位置上是不同的定義,這個界面布局規定三級菜單就是最小的菜單節點了,也就是葉子節點。



要實現以上的菜單,需要把菜單定義成相關的Json數據,然后通過腳本把它們添加到界面里面去,如下數據和腳本就是定義相關的菜單數據的。

<script type="text/javascript">
var _menus = {
    "default": [
        {
            "menuid": "1", "icon": "icon-computer", "menuname": "權限管理",
            "menus": [
                      { "menuid": "13", "menuname": "用戶管理", "icon": "icon-user", "url": "/User/Index" },
                      { "menuid": "14", "menuname": "組織機構管理", "icon": "icon-organ", "url": "/OU/Index" },
                      { "menuid": "15", "menuname": "角色管理", "icon": "icon-group-key", "url": "/Role/Index" },
                      { "menuid": "16", "menuname": "功能管理", "icon": "icon-key", "url": "/Function/Index" },
                      { "menuid": "17", "menuname": "登陸日志", "icon": "icon-view", "url": "/LoginLog/Index" }
            ]
        },
       {
           "menuid": "2", "icon": "icon-user", "menuname": "其他管理",
           "menus": [{ "menuid": "21", "menuname": "修改密碼", "icon": "icon-lock", "url": "javascript:ShowPasswordDialog()" }
           ]
       }
    ],
    "point": [
        {
            "menuid": "3", "icon": "icon-computer", "menuname": "事務中心",
            "menus": [
                      { "menuid": "33", "menuname": "測試菜單1", "icon": "icon-user", "url": "../Commonpage/building.htm" },
                      { "menuid": "34", "menuname": "測試菜單2", "icon": "icon-organ", "url": "../Commonpage/building.htm" },
                      { "menuid": "35", "menuname": "測試菜單3", "icon": "icon-group-key", "url": "../Commonpage/building.htm" },
                      { "menuid": "36", "menuname": "測試菜單4", "icon": "icon-key", "url": "../Commonpage/building.htm" }
            ]
        },
        {
            "menuid": "4", "icon": "icon-user", "menuname": "其他菜單",
            "menus": [{ "menuid": "41", "menuname": "測試菜單5", "icon": "icon-lock", "url": "../Commonpage/building.htm" }]
        }
    ]
};

function showSubMenu(url, title, menuCategory, defaultIcon) {
    if (defaultIcon == null || defaultIcon == "") {
        defaultIcon = "icon-table";
    }
    addTab(title, url, "icon " + defaultIcon);
    Clearnav();
    if (menuCategory != "") {
        addNav(_menus[menuCategory]);
    }
}
</script>

從上面的菜單Json數據來看,它是一個字典的Json數據列表,在Web界面上,通過下面的代碼可以展開上面Json定義的二級菜單。

<li><a href="#" onclick="showSubMenu('/User/Index', '用戶管理', 'default')">權限管理</a></li>

雖然上面的定義的數據能夠解決菜單的顯示問題,但是對于我們需要動態控制的菜單,顯然做不到,因此需要把上面的json數據,通過菜單控制器進行動態生成才可以,然后在腳本里面通過Jquery的方式獲取Json數據,如下所示。

var _menus = {};
//同步獲取
$.ajax({
    type: 'GET',
    url: '/Menu/GetMenuData?r=' + Math.random(),
    async: false,//同步
    dataType: 'json',
    success: function (json) {
        _menus = json;
    },
    error: function (xhr, status, error) {
        alert("操作失敗"); //xhr.responseText
    }
});

上面的GetMenuData方法,通過后臺的控制器進行動態生成的,它的代碼如下所示

/// <summary>
/// 獲取樹形展示數據
/// </summary>
/// <returns></returns>
public ActionResult GetMenuData()
{
    string json = GetTreeJson("-1", "", "");
    json = json.Trim(',');
    return Content(string.Format("[{0}]", json));
}

/// <summary>
/// 遞歸獲取樹形信息
/// </summary>
/// <returns></returns>
private string GetTreeJson(string PID, string folderIcon, string leafIcon)
{
    string condition = string.Format("PID='{0}' ", PID);
    List<MenuInfo> nodeList = BLLFactory<Menu>.Instance.Find(condition);
    StringBuilder content = new StringBuilder();
    foreach (MenuInfo model in nodeList)
    {
        string ParentID = (model.PID == "-1" ? "0" : model.PID);
        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();
}

不過對于上面的代碼,我覺得雖然能解決問題,能夠正確生成相關的Json代碼,但是感覺不夠優雅,我不喜歡使用拼湊方法構建數據。

前面看了Menu的Json腳本,我說過他是一個字典類型的Json數據格式,那么我們是否可以通過字典和實體信息來承載,然后直接通過ToJson方法出來呢?答案是可以的。

/// <summary>
/// 獲取菜單的樹形展示數據
/// </summary>
/// <returns></returns>
public ActionResult GetMenuData()
{
    Dictionary<string, List<MenuData>> dict = new Dictionary<string, List<MenuData>>();
                                             
    List<MenuInfo> list = BLLFactory<Menu>.Instance.GetTopMenu(MyConstants.SystemType);
    int i = 0;
    foreach (MenuInfo info in list)
    {
        if (!HasFunction(info.FunctionId))
        {
            continue;
        }              
        List<MenuData> treeList = new List<MenuData>();
        List<MenuNodeInfo> nodeList = BLLFactory<Menu>.Instance.GetTreeByID(info.ID);
        foreach (MenuNodeInfo nodeInfo in nodeList)
        {
            if (!HasFunction(nodeInfo.FunctionId))
            {
                continue;
            }                                                                                                                                                                       
            MenuData menuData = new MenuData(nodeInfo.ID, nodeInfo.Name, string.IsNullOrEmpty(nodeInfo.WebIcon) ? "icon-computer" : nodeInfo.WebIcon);
            foreach (MenuNodeInfo subNodeInfo in nodeInfo.Children)
            {
                if (!HasFunction(subNodeInfo.FunctionId))
                {
                    continue;
                }
                string icon = string.IsNullOrEmpty(subNodeInfo.WebIcon) ? "icon-organ" : subNodeInfo.WebIcon;
                menuData.menus.Add(new MenuData(subNodeInfo.ID, subNodeInfo.Name, icon, subNodeInfo.Url));
            }
            treeList.Add(menuData);
        }

        //添加到字典里面,如果是第一個,默認用default名稱
        string dictName = (i++ == 0) ? "default" : info.ID;
        dict.Add(dictName, treeList);
    }

    string content = ToJson(dict);
    return Content(content.Trim(','));
}

上面的代碼,通過MenuData的對象數據,來承載相關的菜單信息,然后把它添加到字典Dictionary<string, List<MenuData>> dict 里面就可以了,這樣的代碼,沒有那么多拼湊出來的感覺,是不是很好看呢?把對象轉換為Json數據,直接通過ToJson就可以解決了,很簡單吧。

而菜單的權限控制,就是通過集合權限管理進行判斷,父菜單如果沒有權限,就直接跳過,不在繼續生成下面的子菜單,權限判斷的如下所示。

if (!HasFunction(info.FunctionId))
{
       continue;
 } 

當然,在界面上展開二級菜單的操作界面,也應該通過腳本動態進行生成的,這樣才能做到所有的內容動態構建。

<ul class="navigation" style="display:block">
    @Html.Raw(@ViewBag.HeaderScript)</ul>

上面使用ViewBag對象進行傳遞腳本內容到界面上,其實后臺生成的操作,是一行HTML代碼就是了,代碼類似下面的內容。

<li>
    <a href="#" onclick="showSubMenu('/User/Index', '用戶管理', 'default')">權限管理</a>
</li>

最后出來的效果,就是博客開始介紹的界面截圖,沒有任何變化,但是代碼我們已經經過了幾步的優化整理,看起來很清爽,更能實現動態變化了。


有空可以回顧下其他兩篇的經驗總結內容:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容