operamasks-ui2.0 +MVC4.0+EF5.0實戰之二 功能菜單及樹形控件(Tree)


  上篇中介紹了使用omBorderLayout控件實現了系統總體布局,下面我們就來說一下使用樹形控件Tree來實現布局左側區域的功能菜單(注:本文中不考慮功能菜單的權限控制,此部分內容待日后加上)。

  功能菜單是一個系統必不可少的部分,通常包括兩級,第一級通常為模塊名稱,第二級為功能名稱,復雜的系統往往會進一步擴展到三級甚至四級。對於軟件系統,這是一種常見模式,實體通過自關聯,實現無限極擴展,前台通過樹形控件來展現。 

  采用樹形控件對數據進行展現,有兩種選擇,一種是一次性讀取所有數據,另一種是逐級加載。對於一個系統的功能菜單來說,充其量也就是幾十項,一次性讀取出來,也完全沒有性能問題,因此沒必要采取異步方式,逐級加載。對於小數據量,采取逐級異步加載方式,需要頻繁訪問后台以及進行數據庫讀取,一般來說,反而會比一次性讀取消耗更多的資源。

  首先說一下前台需要做的工作,在Home控制器的Index視圖里,做以下操作:

  1.在head標簽內部加入對om相關css樣式表的引用

    @Styles.Render("~/OperaMasksUI/css/default/om-default.css")     

  2.在</body>標簽之前加入以下對js文件的引用

      @Scripts.Render("~/OperaMasksUI/js/jquery163.min.js")

          @Scripts.Render("~/OperaMasksUI/js/operamasks-ui200.min.js")

  3.在前面布局控件的左側區域中,加入一個ul元素,如下所示

        <div id="west-panel">

            <ul id="tree"></ul>

        </div>

  4.編寫js如下:  

     //初始化
        $(function ()
        {
            //初始加載
            LoadLayout();//上節已說的布局控件
            LoadTree();//本節正在說的樹控件
            LoadTabs();//下節將要說的tab控件 
        }); 
    function LoadTree()
        {
            $("#tree").omTree({
                simpleDataModel: true,
                dataSource: '@Url.Action("GetMenu")',
                onClick: TreeNodeClick
            });
        }

  treenode 支持兩種json格式。
  第一種為:

{
    text:'node1', // 樹節點顯示文本,必需
    expanded:true, // 是否默認展開,非必須,默認值是false
    classes:'folder', // 樹節點樣式,非必需,默認有folder和file,如果用戶自定制為其他,則顯示用戶自定義樣式
    children:childrenDataArray, //子節點,非必需。緩加載時可以沒有這個屬性 
    hasChildren: false // 是否有子節點,非必需,如果值為true表示要緩加載此時可以沒有children屬性
} 

  第二種為:

{
    id:'n1', //樹節點的標識,必需
    pid: 'n0' //父節點id,非必需,如果沒有設置該節點就為根節點
    text:'node1', // 樹節點顯示文本,必需
    expanded:true, // 是否默認展開,非必須,默認值是false
    classes:'folder' // 樹節點樣式,非必需,默認有folder和file,如果用戶自定制為其他,則顯示用戶自定義樣式
} 

  在這里我使用了第二種方式,即指明父節點(pid)方式,特別注意,采用這種方式,需要將simpleDataModel屬性設置為true。dataSource屬性可以是靜態的json對象,也可以是遠程的服務器地址,這里我使用了@Url.Action調用了一個后台方法GetMenu來獲取數據。至於onClick: TreeNodeClick,這里是指定樹節點點擊后進行處理的函數,將在下節里跟tab控件一起進行說明,你這里可以寫一個簡單alert來查看效果 function TreeNodeClick(node,event){alert(“點擊:”+node.id);}。 

  

  上面說的都是關於前台的操作,下面說一下后台相關操作。 

  采用Code First模式,首先創建菜單實體  

using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;

namespace Model.Sys
{
    public class Menu
    {
        [DisplayName("內碼")]
        public string ID { get; set; }

        [DisplayName("名稱")]
        public string Name { get; set; }

        [DisplayName("地址")]
        public string Url { get; set; }

        [DisplayName("上級內碼")]
        public string ParentID { get; set; }

        public virtual Menu ParentMenu { get; set; }

        [ForeignKey("ParentID")]
        public virtual ICollection<Menu> SonMenus { get; set; }

    }
}

  然后在數據庫里插入幾條測試數據(以下是使用EntityFramework的遷移功能,在Configuration類的Seed方法里加入測試數據,關於遷移功能請參見我之前的一篇譯稿前半部分 Asp.Net MVC4.0 官方教程 入門指南之八--為Movie模型和庫表添加字段),當然你也可以在數據庫里手工添加。           

context.Menu.AddOrUpdate
( p
=> p.ID, new Menu { ID = "2", Name = "系統管理" }, new Menu { ID = "3", Name = "部門管理", ParentID = "2", Url = "/Sys/Department/ListPage" }, new Menu { ID = "4", Name = "人員管理", ParentID = "2" }, new Menu { ID = "5", Name = "菜單管理", ParentID = "2" }
);

  為了構建om樹節點對應的json數據,新定義一個類,名字就叫TreeNode  

    public class TreeNode
    {
        public string id { get; set; }
        public string pid { get; set; }
        public string text { get; set; }
        public string expanded { get; set; }
        public string classes { get; set; }
        public string url { get; set; }
    }

  url是我自己附加的額外屬性,用於指明鏈接地址的,其他幾項是官方標准屬性,一看名字就知道大概含義了,在om主頁中可以查看具體說明、含義和取值范圍。

  最后來看一下位於Home控制器里的GetMenu方法      

     public ActionResult GetMenu()
        {
            IQueryable<Menu> menu = MenuService.Query();
            var nodes = new List<TreeNode>();
            foreach (var item in menu.ToList())
            {
                TreeNode node = new TreeNode();
                node.id = item.ID;
                node.pid = item.ParentID;
                node.text = item.Name;
                node.url = item.Url;
                node.expanded = "true";              
                nodes.Add(node);
            }
            return Content(nodes.ToJsonString());           
        }

  上面這個方法中第一句是調用了我后台服務方法,實質等同於EF上下文對象context.Menu.AsQueryable(),即取得所有數據。至於最后一句,則是使用了擴展方法,給object對象加了一個ToJsonString()方法,這樣就可以像調用ToString()方法一樣進行json轉換了。

using System;
using System.Text;
using System.Web.Script.Serialization;


namespace Common.Extentions
{
    public static class ObjectExtentions
    {
        public static string ToJsonString(this Object obj)
        {
            JavaScriptSerializer s = new JavaScriptSerializer();
            StringBuilder sb = new StringBuilder();
            s.Serialize(obj, sb);
            return sb.ToString();
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM