【開源】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, width: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中,就能滿足需求,在Views\Roles\Index.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: "編號", width: 40, halign: "center", align: "right", sortable: true },
14             { field: "Name", title: "角色名", width: 150, sortable: true },
15             { field: "Remark", title: "角色描述", width: 150, sortable: true },
16             { field: "CreatedTime", title: "創建時間", width: 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, width: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: "編號", width: 40, halign: "center", align: "right", sortable: true },
3     { field: "Name", title: "角色名", width: 150, sortable: true, editor: { type: "validatebox", options: { required: true, validType: "length[1,50]" } } },
4     { field: "Remark", title: "角色描述", width: 150, sortable: true, editor: { type: "textarea", options: { validType: "length[1,500]" } } },
5     { field: "CreatedTime", title: "創建時間", width: 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快速開發框架解說系列


免責聲明!

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



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