zoukankan      html  css  js  c++  java
  • 【开源】OSharp框架解说系列(2.2):EasyUI复杂布局及数据操作

    OSharp是什么?

      OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现。与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现。依赖注入、ORM、对象映射、日志、缓存等等功能,都只定义了一套最基础最通用的抽象封装,提供了一套统一的API、约定与规则,并定义了部分执行流程,主要是让项目在一定的规范下进行开发。所有的功能实现端,都是通过现有的成熟的第三方组件来实现的,除了EntityFramework之外,所有的第三方实现都可以轻松的替换成另一种第三方实现,OSharp框架正是要起隔离作用,保证这种变更不会对业务代码造成影响,使用统一的API来进行业务实现,解除与第三方实现的耦合,保持业务代码的规范与稳定。

    本文已同步到系列目录:OSharp快速开发框架解说系列

    EasyUI复杂布局

       接上篇,前面我们已经定义了一个 datagrid父视图 _DataGridLayout.cshtml,实现一个表格是相当的容易。但是,实际业务中,并非所有的数据列表并非只是单一的datagrid列表,还可能需要把datagrid与其他组件配合使用,比如角色信息是来源于各个组织机构的,就需要增加一个组织机构的分类,来更好的管理各种角色。最终效果图如下:
      

      来分析一下这个页面,不难看出,需要将选项卡Tab的内容页拆分成另外一个由左+内容的 easyui-layout 构成的布局页,左部分是组织机构的树型导航栏,右边是相应的角色列表。

      我们先来分析一下前后的html变化,只有一个datagrid的时候,html很简单,只有一行:

    1 <div id="grid-roles"></div>

      要满足上面的需求,html变成了:

    1 <div id="layout-roles" class="easyui-layout" data-options="fit:true">
    2     <div data-options="region:'west', split:true, minWidth:80, 150, title:'组织机构'">
    3         <ul id="tree-organizations" class="easyui-tree"></ul>
    4     </div>
    5     <div data-options="region:'center', border:false">
    6         <div id="grid-roles"></div>    
    7     </div>
    8 </div>

      这个而已,原先的 _DataGridLayout.cshtml 还能胜任吗?答案是肯定的,因为我们已经预先做好了准备,_DataGridLayout.cshtml 中有如下定义:

      

      只需要把 #grid-roles 前后的代码分别回到 headHtml 与 footHtml 两个Section中,就能满足需求,在ViewsRolesIndex.cshtml中添加如下代码:

      

      注意,在html已经被拆分成了两部分,单一部分肯定是不闭合的,会处于报错状态,但一定要保证组合起来之后是闭合的,才能生成正确的 html。

      当然,还要按需要添加处理新添加的 easyui-layout 和 easyui-tree 的 javascript 代码,这就要用到 _DataGridLayout.cshtml 中定义的 startfunction() 与 endfunction() 两个方法了,要添加的代码也很简单,只要选择组织机构的树节点的时候变更datagrid的URL即可:

      

       综合之后,角色列表视图的代码组织如下:

     1 @{
     2     ViewBag.Title = "角色信息列表";
     3     Layout = "~/Areas/Admin/Views/Shared/_DataGridLayout.cshtml";
     4 
     5     ViewBag.GridId = "roles";
     6     ViewBag.GridDataUrl = Url.Action("GridData");
     7     ViewBag.NodeDataUrl = Url.Action("NodeData", "Organizations");
     8 }
     9 @section customScript
    10 {
    11     <script type="text/javascript">
    12         columns = [[
    13             { field: "Id", title: "编号",  40, halign: "center", align: "right", sortable: true },
    14             { field: "Name", title: "角色名",  150, sortable: true },
    15             { field: "Remark", title: "角色描述",  150, sortable: true },
    16             { field: "CreatedTime", title: "创建时间",  150, halign: "center", align: "center", sortable: true, formatter: function (value) { return $.osharp.tools.formatDate(value); } }
    17         ]];
    18 
    19         endfunction = function () {
    20             var $tree = $("#tree-@ViewBag.TreeId");
    21             $tree.tree({
    22                 url: "@ViewBag.NodeDataUrl",
    23                 onSelect:function(node) {
    24                     grid.datagrid({
    25                         url: "@ViewBag.GridDataUrl/" + node.id
    26                     });
    27                 }
    28             });
    29         };
    30     </script>
    31 }
    32 @section headHtml
    33 {
    34     <div id="layout-@ViewBag.GridId" class="easyui-layout" data-options="fit:true">
    35         <div data-options="region:'west', split:true, minWidth:80, 150, title:'组织机构'">
    36             <ul id="tree-@ViewBag.TreeId" class="easyui-tree"></ul>
    37         </div>
    38         <div data-options="region:'center', border:false">
    39 }
    40 @section footHtml
    41 {
    42         </div>
    43     </div>
    44 }
    View Code

       运行效果如图:

       

    EasyUI动态工具栏

       表格的工具栏  的项,由 _DataGridLayout.cshtml 中的 1 string toolbarItem = ViewBag.ToolbarItem ?? "add,edit,save,cancel,delete"; 控制,需要重新定义的时候,在 子视图中重新定义ViewBag.ToolbarItem 即可。生成项的代码如下:

     1 var toolbarData = [
     2     @if (toolbarItem.Contains("add"))
     3     {
     4         @:{ text: "增加", iconCls: "icon-add", handler: addNewRow },
     5     }
     6     @if (toolbarItem.Contains("edit"))
     7     {
     8     <text>
     9     { text: "编辑", iconCls: "icon-edit", handler: beginEdit },
    10     "-",
    11     </text>
    12     }
    13     @if (toolbarItem.Contains("save"))
    14     {
    15         @:{ text: "保存", iconCls: "icon-save", handler: saveChanges },
    16     }
    17     @if (toolbarItem.Contains("cancel"))
    18     {
    19         <text>
    20     { text: "取消", iconCls: "icon-undo", handler: cancelEdit },
    21     "-",
    22     </text>
    23     }
    24     @if (toolbarItem.Contains("delete"))
    25     {
    26         @:{ text: "删除", iconCls: "icon-remove", handler: deleteRows },
    27     }
    28 ];

      如果需要给添加额外表格操作,可以在子视图中重写 startfunction() 方法,添加相应的按钮项和功能函数即可:

    1 startfunction = function () {
    2     //导出
    3     function exportRoles() {
    4         $.osharp.easyui.msg.info("导出角色数据");
    5     }
    6     toolbarData.push({ text: "导出", iconCls: "pic_50", handler: exportRoles });
    7 };

      这样,就能根据用户的权限动态的决定用户有哪些可用功能,运行效果如下:

      

    EasyUI增删改操作

    前端部分

      在本示例中,表格数据的操作尽量使用 行内编辑 的方式来进行,如部分数据需要别的方式(比如弹出窗口的编辑方式),可在子视图中对工具栏按钮事件进行重写。

      行内编辑,需要在子视图的 columns 信息中添加编辑及数据验证的相关设置 editor,具体参考 easyui 的api说明,这里略过,如下:

    1 columns = [[
    2     { field: "Id", title: "编号",  40, halign: "center", align: "right", sortable: true },
    3     { field: "Name", title: "角色名",  150, sortable: true, editor: { type: "validatebox", options: { required: true, validType: "length[1,50]" } } },
    4     { field: "Remark", title: "角色描述",  150, sortable: true, editor: { type: "textarea", options: { validType: "length[1,500]" } } },
    5     { field: "CreatedTime", title: "创建时间",  150, halign: "center", align: "center", sortable: true, formatter: function (value) { return $.osharp.tools.formatDate(value); } }
    6 ]];

      easyui 的表格验证还是不错的,比如添加一行,效果如下:

      

      向后端提交数据,这里使用 json2.js 的 JSON.stringify(data) 将数据序列化成 json 之后再提交,删除的时候提交的数据为 id 的集合,是先使用 jquery.linq.js(linq to js,能像 C# 使用 linq 一样使用 js 来操作集合数据)来提取 id 的集合,再进行序列化提交,实现如下:

     1 function submitAdds(objs) {
     2     $.post("@ViewBag.AddUrl", { dtos: JSON.stringify(objs) }, ajaxResultHandler);
     3 }
     4 
     5 function submitEdits(objs) {
     6     $.post("@ViewBag.EditUrl", { dtos: JSON.stringify(objs) }, ajaxResultHandler);
     7 }
     8 
     9 var deleteRows = function () {
    10     var selectRows = grid.datagrid("getSelections");
    11     if (selectRows.length == 0) {
    12         $.osharp.easyui.msg.tip("请先选中要删除的行。");
    13         return;
    14     }
    15     var ids = $.Enumerable.From(selectRows).Select(function (m) { return m.Id; }).ToArray();
    16     $.osharp.easyui.msg.confirm("是否要删除所有选中的行?此操作是不可恢复的。", null, function () {
    17         $.post("@ViewBag.DeleteUrl", { ids: JSON.stringify(ids) }, ajaxResultHandler);
    18     });
    19 };
    20 
    21 function ajaxResultHandler(data) {
    22     if (data.Type == "Success") {
    23         grid.datagrid("reload");
    24     }
    25     if (data.Type == "Error") {
    26         $.osharp.easyui.msg.error(data.Content);
    27     } else {
    28         $.osharp.easyui.msg.tip(data.Content);
    29     }
    30 }

    后端部分

      后端接收到的数据为JSON字符串,需要解析成Dto,才能进行业务处理,定义了一个JsonBinder类来专门解析前端传来的JSON数据:

     1 /// <summary>
     2 /// JSON数据绑定类
     3 /// </summary>
     4 public class JsonBinder<T> : IModelBinder
     5 {
     6     /// <summary>
     7     /// 使用指定的控制器上下文和绑定上下文将模型绑定到一个值。
     8     /// </summary>
     9     /// <returns>
    10     /// 绑定值。
    11     /// </returns>
    12     /// <param name="controllerContext">控制器上下文。</param><param name="bindingContext">绑定上下文。</param>
    13     public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    14     {
    15         string json = controllerContext.HttpContext.Request.Form[bindingContext.ModelName];
    16         if (string.IsNullOrEmpty(json))
    17         {
    18             json = controllerContext.HttpContext.Request.QueryString[bindingContext.ModelName];
    19         }
    20         if (string.IsNullOrEmpty(json))
    21         {
    22             return null;
    23         }
    24         JsonSerializer serializer = new JsonSerializer();
    25         if (json.StartsWith("{") && json.EndsWith("}"))
    26         {
    27             JObject jsonBody = JObject.Parse(json);
    28             object result = serializer.Deserialize(jsonBody.CreateReader(), typeof(T));
    29             return result;
    30         }
    31         if (json.StartsWith("[") && json.EndsWith("]"))
    32         {
    33             List<T> list = new List<T>();
    34             JArray jsonArray = JArray.Parse(json);
    35             if (jsonArray != null)
    36             {
    37                 list.AddRange(jsonArray.Select(jobj => serializer.Deserialize(jobj.CreateReader(), typeof(T))).Select(obj => (T)obj));
    38             }
    39             return list;
    40         }
    41         return null;
    42     }
    43 }

       后台处理代码如下,这里还没有进行真正的业务逻辑处理,只是简单的返回一个结果:

     1 [HttpPost]
     2 [AjaxOnly]
     3 public ActionResult Add([ModelBinder(typeof(JsonBinder<RoleDto>))] ICollection<RoleDto> dtos)
     4 {
     5     string[] names = dtos.Select(m => m.Name).ToArray();
     6     AjaxResult result = new AjaxResult("角色“{0}”新增成功".FormatWith(names.ExpandAndToString()), AjaxResultType.Success);
     7     return Json(result, JsonRequestBehavior.AllowGet);
     8 }
     9 
    10 [HttpPost]
    11 [AjaxOnly]
    12 public ActionResult Edit([ModelBinder(typeof(JsonBinder<RoleDto>))] ICollection<RoleDto> dtos)
    13 {
    14     string[] names = dtos.Select(m => m.Name).ToArray();
    15     AjaxResult result = new AjaxResult("角色“{0}”新增成功".FormatWith(names.ExpandAndToString()), AjaxResultType.Success);
    16     return Json(result, JsonRequestBehavior.AllowGet);
    17 }
    18 
    19 [HttpPost]
    20 [AjaxOnly]
    21 public ActionResult Delete([ModelBinder(typeof(JsonBinder<int>))] ICollection<int> ids)
    22 {
    23     AjaxResult result = new AjaxResult("{0} 个角色删除成功".FormatWith(ids.Count), AjaxResultType.Success);
    24     return Json(result, JsonRequestBehavior.AllowGet);
    25 }

      返回的AjaxResult是一个专用封装于AJAX操作结果的类型:

     1 /// <summary>
     2 /// 表示Ajax操作结果 
     3 /// </summary>
     4 public class AjaxResult
     5 {
     6     /// <summary>
     7     /// 初始化一个<see cref="AjaxResult"/>类型的新实例
     8     /// </summary>
     9     public AjaxResult(string content, AjaxResultType type = AjaxResultType.Info, object data = null)
    10         : this(content, data, type)
    11     { }
    12 
    13     /// <summary>
    14     /// 初始化一个<see cref="AjaxResult"/>类型的新实例
    15     /// </summary>
    16     public AjaxResult(string content, object data, AjaxResultType type = AjaxResultType.Info)
    17     {
    18         Type = type.ToString();
    19         Content = content;
    20         Data = data;
    21     }
    22 
    23     /// <summary>
    24     /// 获取 Ajax操作结果类型
    25     /// </summary>
    26     public string Type { get; private set; }
    27 
    28     /// <summary>
    29     /// 获取 消息内容
    30     /// </summary>
    31     public string Content { get; private set; }
    32 
    33     /// <summary>
    34     /// 获取 返回数据
    35     /// </summary>
    36     public object Data { get; private set; }
    37 }

       操作结果,成功返回结果,测试通过:

      

      至此,EasyUI的界面搭建基本完成,后面的文章中我们将使用这个界面构建一个会员系统,欢迎关注。

    开源说明

    github.com

       OSharp项目已在github.com上开源,地址为:https://github.com/i66soft/osharp,欢迎阅读代码,欢迎 Fork,如果您认同 OSharp 项目的思想,欢迎参与 OSharp 项目的开发。

      在Visual Studio 2013中,可直接获取 OSharp 的最新源代码,获取方式如下,地址为:https://github.com/i66soft/osharp.git

      

    nuget

      OSharp的相关类库已经发布到nuget上,欢迎试用,直接在nuget上搜索 “osharp” 关键字即可找到
      

    系列导航

    本文已同步到系列目录:OSharp快速开发框架解说系列

  • 相关阅读:
    mysql常用命令
    CSS样式
    定位
    background
    文本属性和字体属性
    超链接导航案例
    margin塌陷
    浮动
    GIT 修改提交地址
    VUE ElementUI 表格多选框实现单选
  • 原文地址:https://www.cnblogs.com/guomingfeng/p/osharp-easyui-opera.html
Copyright © 2011-2022 走看看