好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

转载operamasksui2.0 +MVC4.0+EF5.0实战之三 业务功能区域及标签页控件(t

转载operamasksui2.0 +MVC4.0+EF5.0实战之三 业务功能区域及标签页控件(tab)

上篇中完成了功能菜单的树形展现,下面说一下系统布局中心区域主业务功能区,通过使用标签页控件来实现打开多个tab页的方式,以便进行系统操作和业务办理。  

  首先说一下前台tab控件的初始化工作,在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  ="center-panel"   > 
             <  div   id  ="tabs"  > 
                <  ul  > 
                     <  li  ><  a   href  ="#tab1"  > 欢迎使用 </  a  ></  li  > 
                 </  ul  > 
                 <  div   id  ="tab1"  >  
                    欢迎使用MVC开发框架
                  </  div  > 
             </  div  > 
         </  div  > 

    注意:这里如果只加<div id="tabs"></div>,则会导致功能异常,应该是om框架自身不完善性造成的,我这边是加了一个默认tab放置欢迎信息,当然你也可以放站点地图或者系统说明。

  4.编写js如下: 

         function LoadTabs()
        {
            $('#tabs').omTabs({
                 'fit',
                height: 'fit',               
                closable: true
            });
        } 

  width和height默认属性为auto,我改为了'fit',即自动填充满父容器,这样看上去能美观一些。

  以上操作完成了tab页控件初始化工作,下面重点来说一下与tree控件配合实现多个业务功能页面打开的效果。

  为树节点添加点击事件,点击后自动在中心区域tab控件里自动添加一个tab页,采取嵌入iframe方式,打开功能菜单对应的url地址,以下这么写完成了基本功能:  

 function   TreeNodeClick(node, event)
 {
      $( "#tabs").omTabs('add' , {
      title: node.text,
      content:  '<iframe scrolling="yes" frameborder="0"  src=' + node.url + ' style="100%;height:100%;"></iframe>' ,
      closable:   true  ,
      tabId:node.id
      });
} 

  tab页标题直接使用功能菜单名称即可,content里嵌入iframe,添加tabId唯一性标识是用于下文来判断当前点击的功能菜单树节点是否在tabs控件中已打开过。

  之所以说完成基本功能,还有一些细节需要考虑的,加入两个逻辑,一是需要判断树节点是不是叶子节点,如果是菜单分类,则不执行操作,否则执行tab控件相关操作。二是需要判断当前tab控件列表中是否已存在当前要打开功能菜单,若不存在,添加新tab页并在其中打开,若已存在,则只需令其激活,变为当前展现的tab页即可。

  第一点判断是否为叶节点,这里有种简便的方式,即判断节点url属性是否为空,若为空,则认为是菜单分类。实际上,这里并不是严格意义上判断叶子节点逻辑,而是取巧的方式,不过这种方式具有更好的灵活性,例如,若菜单分类也加了url属性,则同样可以点击打开对应的功能页面。

  第二点判断是否已打开过,则om控件没提供简便的方法,需要运用提供的现有的方法来自己完成,实现如下:  

         function   CheckTabsExist(currentTabId)
        {
              var  total = $('#tabs').omTabs('getLength' );            
              for  (i = 0; i < total; i++ )
            {
                  var  tabId = $('#tabs').omTabs('getAlter' , i);                
                  if  (tabId ==  currentTabId)
                {
                      return   true  ;
                }                
            }
              return   false  ;
        } 

  完善后的树节点点击处理方法如下:

  

 function   TreeNodeClick(node, event)
        {
              if   (node.url)
            {                
                  if   (CheckTabsExist(node.id))
                {
                      var  index = $('#tabs').omTabs('getAlter' , node.id);                  
                    $( "#tabs").omTabs('activate' , index);
                }
                  else  
                {
                    $( "#tabs").omTabs('add' , {
                        title: node.text,
                        content:  '<iframe scrolling="yes" frameborder="0"  src=' + node.url + ' style="100%;height:100%;"></iframe>' ,
                        closable:   true  ,
                        tabId: node.id
                    });
                }
            }           
        } 

  如上所示,若已存在,则激活,若不存在,则添加新标签。

  当打开的tab标签页越来越多,就产生了一个新需求,即批量关闭标签,跟浏览器类似,这需求可以通过添加右键菜单来实现。只需要在tab控件初始化LoadTabs里加入属性 tabMenu:true即可,然后在tab标签页头部点击右键,就会出现“关闭”、“关闭其他”、“关闭所有”三个菜单,如果你要实现浏览器关闭左侧和右侧,om现有控件没提供该功能,需要你自己去扩展了。

  最后,说一下跟easyui的区别吧。至目前为止,已经将easyui的三个控件layout、tree、tab替换为om了,个人观点,easy更人性化,完善性更好。人性化体现在,默认属性尽可能贴近实际情景,比如,是否自动填充父窗体,而不需要用户再额外指定。完善行则体现在各种情况的应对,起码,我在使用easyuri过程中,就没发现js报错的情况,而使用om,则经常出现,往往是一些宽度和高度无法获取,比如实战一中,一个div标签,没内容闭包报错,使用tab控件的时候,如果只写一个div,则初始化的时候,会报scroller(滚动条)获取长度出错。还有更关键的一点,就是提供的属性和方法是否更符合开发者的需要,以本文中树节点点击事件为例,以下是我使用easyui写的处理:

           var  node = $('#mainMenu').tree('getSelected' );
               var  isLeaf = $('#mainMenu').tree('isLeaf' , node.target);
               if  (isLeaf ==  true  )
             {
                   if  ($("#mainTabs").tabs('exists', node.text) ==  false  )
                 {
                     $( "#mainTabs").tabs('add' , {
                         title: node.text,
                         content:  '<iframe scrolling="yes" frameborder="0"  src=' + node.attributes + ' style="100%;height:100%;"></iframe>' ,
                         closable:   true  ,
                         cache:   false  
                     });
                 }
                   else  
                 {
                     $( "#mainTabs").tabs('select' , node.text);
                 }
             } 

  首先获取当前点击值,判断是否是叶节点,有现成的方法可用,判断tab标签页中是否已存在打开的菜单,也有现成的方法可用,而om则显得笨拙多了,两个逻辑都要自己写,对开发者的友好性明显有一定差距。这里也并不是说om比easyui差,om也提供了一些更强大的功能,我仅是从自己的业务需要和功能规划,对用到的功能点进行简单对比,觉得easyui更胜一筹。

 

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();
        }
    }
} 

 

 

分类:  MVC4.0

标签:  MVC EntityFramework JQuery 开发框架 operamasks-ui tree

 

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于转载operamasksui2.0 +MVC4.0+EF5.0实战之三 业务功能区域及标签页控件(t的详细内容...

  阅读:41次