愛(ai)上MVC3~MVC+ZTree實現(xian)對樹的CURD及拖拽操(cao)作
上一講中,我們學習(xi)了如何使(shi)用zTree對一棵(ke)大(da)樹(大(da)數據(ju)量的樹型結構的數據(ju)表,呵(he)呵(he),名稱有點(dian)繞,但說(shuo)的是事實)進(jin)行異步(bu)加(jia)載,今天(tian)這講,我們來(lai)說(shuo)說(shuo),如何去(qu)操作(zuo)這棵(ke)大(da)樹,無非就是添加(jia)子節點(dian),刪除節點(dian),編(bian)輯節點(dian),節點(dian)之間的拖(tuo)拽,節點(dian)位置的變化(排序)等等。
事(shi)實上(shang),jquery.ZTree的(de)(de)demo已經(jing)把前臺(tai)JS代碼(ma)(ma)給(gei)的(de)(de)很(hen)清晰了(le),我們只要稍加修(xiu)改,然后把后臺(tai)CS代碼(ma)(ma)寫好就可以(yi)了(le),我將demo的(de)(de)前臺(tai)代碼(ma)(ma)做了(le)簡(jian)單(dan)的(de)(de)處理,減(jian)化了(le)些代碼(ma)(ma),項目架構使用microsoft mvc 3.0
前臺HTML代碼(ma)如下:
<link href="../../Scripts/JQuery-zTree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" /> <script src="../../Scripts/JQuery-zTree/js/jquery-1.4.4.min.js"></script> <script src="../../Scripts/JQuery-zTree/js/jquery.ztree.all-3.5.min.js"></script> <style type="text/css"> .ztree li span.button.add { margin-left: 2px; margin-right: -1px; background-position: -144px 0; vertical-align: top; *vertical-align: middle; } a { text-decoration: underline; } </style> <script type="text/javascript"> /* 動態數據測試(shi)部分開(kai)始 */ var log, className = "dark"; var treeID = "treeDemo"; var curDragNodes, autoExpandNode; var newCount = 1; //異步加載節點(dian) var setting4 = { data: { simpleData: { enable: true, idKey: "id", pIdKey: "pId", rootPId: null } }, edit: { enable: true, editNameSelectAll: true, showRemoveBtn: showRemoveBtn, showRenameBtn: showRenameBtn, removeTitle: "刪除", renameTitle: "編輯", drag: { autoExpandTrigger: true, prev: dropPrev, inner: dropInner, next: dropNext } }, view: { addHoverDom: addHoverDom, removeHoverDom: removeHoverDom, selectedMulti: false }, async: { //異步(bu)加載 enable: true, url: "/ZTree/AsyncGetNodes", autoParam: ["id", "name", "pId"] }, callback: { /*節點獲(huo)取與展開回調*/ beforeExpand: beforeExpand, onAsyncSuccess: onAsyncSuccess, onAsyncError: onAsyncError, /*編輯與刪除回調*/ beforeEditName: beforeEditName, beforeRemove: beforeRemove, beforeRename: beforeRename, onRemove: onRemove, onRename: onRename, /*拖動回調(diao)*/ beforeDrag: beforeDrag, beforeDrop: beforeDrop, beforeDragOpen: beforeDragOpen, onDrag: onDrag, onDrop: onDrop, onExpand: onExpand } }; function beforeEditName(treeId, treeNode) { className = (className === "dark" ? "" : "dark"); var zTree = $.fn.zTree.getZTreeObj(treeID); zTree.selectNode(treeNode); return confirm("進入節點 -- " + treeNode.name + " 的編輯狀態嗎?"); } function beforeRemove(treeId, treeNode) { className = (className === "dark" ? "" : "dark"); var zTree = $.fn.zTree.getZTreeObj(treeID); zTree.selectNode(treeNode); return confirm("確認刪除 節點 -- " + treeNode.name + " 嗎?"); } function beforeRename(treeId, treeNode, newName, isCancel) { className = (className === "dark" ? "" : "dark"); if (newName.length == 0) { alert("節點名稱不能為空."); var zTree = $.fn.zTree.getZTreeObj(treeID); setTimeout(function () { zTree.editName(treeNode) }, 10); return false; } return true; } function onRemove(e, treeId, treeNode) { $.ajax({ url: '/ZTree/AsyncDelNodes', //url action是方法的(de)名(ming)稱 data: { id: treeNode.id }, type: 'POST', success: function (data) { alert(data); } }); } function onRename(e, treeId, treeNode, isCancel) { alert("編輯了節點" + treeNode.id + " " + treeNode.name); $.ajax({ url: '/ZTree/AsyncEditNodes', //url action是方法的(de)名稱 data: { id: treeNode.id, name: treeNode.name }, type: 'POST', success: function (data) { alert(data); } }); } function showRemoveBtn(treeId, treeNode) { //return !treeNode.isFirstNode; return true; } function showRenameBtn(treeId, treeNode) { // return treeNode.isLastNode; return true; } function addHoverDom(treeId, treeNode) { var sObj = $("#" + treeNode.tId + "_span"); if (treeNode.editNameFlag || $("#addBtn_" + treeNode.tId).length > 0) return; var addStr = "<span class='button add' id='addBtn_" + treeNode.tId + "' title='add node' onfocus='this.blur();'></span>"; sObj.after(addStr); var btn = $("#addBtn_" + treeNode.tId); if (btn) btn.bind("click", function () { var zTree = $.fn.zTree.getZTreeObj(treeID); zTree.addNodes(treeNode, { id: (100 + newCount), pId: treeNode.id, name: "new node" + newCount }); $.ajax({ url: '/ZTree/AsyncAddNodes', //url action是方(fang)法的名稱 data: { id: (100 + newCount), pid: treeNode.id, name: "new node" + newCount }, type: 'POST', success: function (data) { //異常完成后,刷新父節點(dian)(dian)及下面所有子節點(dian)(dian) zTree.reAsyncChildNodes(treeNode, "refresh"); } }); newCount++; return false; }); }; function removeHoverDom(treeId, treeNode) { $("#addBtn_" + treeNode.tId).unbind().remove(); }; function createTree() { $.ajax({ url: '/ZTree/AsyncGetNodes', //url action是方(fang)法(fa)的名稱 data: { id: 0 }, type: 'Get', dataType: "text", //可以是text,如(ru)果(guo)用(yong)text,返回(hui)的結果(guo)為字符串(chuan);如(ru)果(guo)需要json格(ge)式的,可是設置為json success: function (data) { $.fn.zTree.init($("#" + treeID), setting4, ; }, error: function (msg) { alert(" 數據加載失敗!" + msg); } }); } function beforeExpand(treeId, treeNode) { if (!treeNode.isAjaxing) { return true; } else { alert("zTree 正在下載數據中,請稍后展開節點。。。"); return false; } } function onAsyncSuccess(event, treeId, treeNode, msg) { } function onAsyncError() { alert(" 數據加載失敗"); } $(document).ready(function () { createTree(); }); function dropPrev(treeId, nodes, targetNode) { var pNode = targetNode.getParentNode(); if (pNode && pNode.dropInner === false) { return false; } else { for (var i = 0, l = curDragNodes.length; i < l; i++) { var curPNode = curDragNodes[i].getParentNode(); if (curPNode && curPNode !== targetNode.getParentNode() && curPNode.childOuter === false) { return false; } } } return true; } function dropInner(treeId, nodes, targetNode) { if (targetNode && targetNode.dropInner === false) { return false; } else { for (var i = 0, l = curDragNodes.length; i < l; i++) { if (!targetNode && curDragNodes[i].dropRoot === false) { return false; } else if (curDragNodes[i].parentTId && curDragNodes[i].getParentNode() !== targetNode && curDragNodes[i].getParentNode().childOuter === false) { return false; } } } return true; } function dropNext(treeId, nodes, targetNode) { var pNode = targetNode.getParentNode(); if (pNode && pNode.dropInner === false) { return false; } else { for (var i = 0, l = curDragNodes.length; i < l; i++) { var curPNode = curDragNodes[i].getParentNode(); if (curPNode && curPNode !== targetNode.getParentNode() && curPNode.childOuter === false) { return false; } } } return true; } function beforeDrag(treeId, treeNodes) { className = (className === "dark" ? "" : "dark"); for (var i = 0, l = treeNodes.length; i < l; i++) { if (treeNodes[i].drag === false) { curDragNodes = null; return false; } else if (treeNodes[i].parentTId && treeNodes[i].getParentNode().childDrag === false) { curDragNodes = null; return false; } } curDragNodes = treeNodes; return true; } function beforeDragOpen(treeId, treeNode) { autoExpandNode = treeNode; return true; } function beforeDrop(treeId, treeNodes, targetNode, moveType, isCopy) { className = (className === "dark" ? "" : "dark"); return true; } function onDrag(event, treeId, treeNodes) { className = (className === "dark" ? "" : "dark"); } function onDrop(event, treeId, treeNodes, targetNode, moveType, isCopy) { className = (className === "dark" ? "" : "dark"); $.ajax({ url: '/ZTree/AsyncDragNodes', // url action是方法的名稱(cheng) data: { id: treeNodes[0].id, pid: targetNode.id, name: treeNodes[0].name, moveType: moveType, isCopy: isCopy }, type: 'POST', success: function (data) { } }); } function onExpand(event, treeId, treeNode) { if (treeNode === autoExpandNode) { className = (className === "dark" ? "" : "dark"); } } </script> <div class="zTreeDemoBackground left"> <ul id="treeDemo" class="ztree"></ul> </div>
面各(ge)種JS事件,所對應的(de)MVC代碼如下:
#region 對節點的操作 /// <summary> /// 得到一級子節點 /// </summary> /// <param name="id"></param> /// <returns></returns> public string AsyncGetNodes(int? id) { var model = irepository.GetEntities() .Where(i => i.ParentID == id).OrderBy(i => i.Sortable); return model.ToJson(); } /// <summary> /// 添加節點 /// </summary> /// <param name="id"></param> /// <param name="name"></param> /// <param name="pid"></param> /// <returns></returns> public string AsyncAddNodes(int id, string name, int pid) { try { //得(de)到父對象,但設(she)置它的(de)isParent屬性 irepository.Modify(i => new Category { ID = pid, IsParent = true, }); var entity = new Category { Name = name, ParentID = pid, CreateDate = DateTime.Now, Level = 1, IsParent = false, }; irepository.Add(entity); return entity.ID.ToString(); } catch (Exception ex) { return ex.Message; } } /// <summary> /// 編輯(ji)節點(dian)(重命名) /// </summary> /// <param name="id"></param> /// <param name="name"></param> /// <returns></returns> public string AsyncEditNodes(int id, string name) { try { irepository.Modify(i => new Category { ID = id, Name = name, }); return "操作成功(gong)"; } catch (Exception ex) { return ex.Message; } } /// <summary> /// 刪(shan)除節點 /// </summary> /// <param name="id"></param> /// <returns></returns> public string AsyncDelNodes(int id) { try { irepository.Remove(irepository.GetEntity(i => i.ID == id)); return "操作成功"; } catch (Exception ex) { return ex.Message; } } /// <summary> /// 拖拽(zhuai)節點 /// </summary> /// <param name="id"></param> /// <param name="pid"></param> /// <param name="sortable"></param> /// <returns></returns> public string AsyncDragNodes( int id, int pid, string name, string moveType, bool isCopy) { try { var parent = irepository.GetEntity(i => i.ID == pid); var parentSons = irepository.GetEntities(i => i.ParentID == pid); var current = irepository.GetEntity(i => i.ID == id); if (moveType == "inner") parent.isParent = true; else if (parentSons == null || parentSons.Count() == 0) parent.isParent = false; if (isCopy)//復(fu)制,前臺目前不能實現 { irepository.Add(new Category { ParentID = pid, Name = name, CreateDate = DateTime.Now, }); } else { if (moveType == "inner") { current.ParentID = pid; irepository.Modify(current); } else { current.ParentID = parent.ParentID;//同級移(yi)動時,與目標(biao)節點父ID相(xiang)同 current.Sortable = moveType == "next" ? parent.Sortable + 1 : parent.Sortable - 1; irepository.Modify(current); } } irepository.Modify(parent); return "操作成功"; } catch (Exception ex) { return ex.Message; } } #endregion
好(hao)了,上面的(de)代碼只是(shi)對樹結果做的(de)最基本的(de)操作,其(qi)中(zhong)拖(tuo)拽時的(de)復制操作(按著ctrl鍵(jian),拖(tuo)拽節點(dian)),后臺沒有進(jin)行實現(xian)。