最近公司要求做一個關於后台的管理系統。在這個mvvm模式橫行的年代,雖然這里用jquery做項目可能有點不符合時代的潮流,但是管他呢,能做出來先在說唄(公司以后要改用angular或者vue來統一前端的制作方式),個人覺得jquery還挺好用的。廢話這里就不多敘述了。下面就先來一張完成后的圖片展示一下ztree可以完成的功能。
額····這邊彈出層的陰影是錄制軟件的問題(這邊的前端插件用的是layui,想用的小伙伴可以自行百度layui,順便一提,我這里用的版本是layui 1.0的,現在layui已經更新到2.0版本了,已經有自適應功能了,挺好用的。你問我為什么不用bootstrap?其實這個項目中UI小伙伴給我的時候插件用的是bootstrap,但是本人就先入為主了,還是覺得layui輕便好用,看個人喜好吧)。
忘記了初衷這里是來介紹ztree的,好了,下面先來介紹下ztree的基本信息。
使用ztree的時候可以參考官網的教程來一步步跟着做。zTree官網。詳細的api可以參照着官網來看。
先看ztree的初始化過程:
1 zTreeObj = $.fn.zTree.init($obj, setting, nodes);
這是就是初始加載ztree樹。第一個參數$obj代表的是你需要加載ztree的容器。一般默認是一個div。第二個參數是我們的配置項。下面會詳細介紹,第三個nodes就是我們需要顯示的數據,實際項目中一般都是后台返回的json.
上面展示的功能用到了樹的左鍵點擊,郵件點擊,拖拽3個大的功能點。這里是我項目中寫的setting的內容
1 var setting = { 2 callback : { 3 onClick : zTreeOnClick, 4 onRightClick : zTreeOnRightClick, 5 beforeDrag : zTreeBeforeDrag, 6 beforeDrop : zTreeBeforeDrop, 7 onDrop : zTreeOnDrop,// 如果對象目標不是節點,不會觸發beforeDrop,直接觸發onDrop 8 }, 9 data : { 10 simpleData : { 11 enable : true, 12 idKey : "id", 13 pIdKey : "pId", 14 }, 15 key : { 16 name : "sname" 17 }, 18 keep : { 19 parent : true,//沒有子節點也保持父節點狀態 20 leaf : false 21 } 22 }, 23 edit : { 24 enable : true, 25 showRemoveBtn : false, 26 showRenameBtn : false, 27 drag : { 28 isCopy : false,//拖拽節點不是復制 29 isMove : true,//拖拽節點只是移動 30 prev : true,//可以放到節點前面 31 next : true,//可以放到其他節點后面 32 inner : canInner//能否放到節點里面看回調函數返回的值 33 } 34 }, 35 view : { 36 selectedMulti : false 37 } 38 };
這里常用到的左鍵點擊事件什么的這里就不提了,可以參照官網的例子。這里就記錄下onRightClick事件和onDrop事件。
首先是onRightClick事件,彈出右鍵菜單欄,然后點擊不同的節點郵件的菜單欄還是不同的。點擊菜單欄上的不同的選項觸發不同的事件。首先我們要讓右鍵樹節點在相應的地方產生菜單。不過不用急,這里ztree給我們返回的參數中包含了標准的event,右鍵點擊的節點node,還有點擊tree的Id(如果一個頁面中有多棵樹,這個參數就顯得十分重要,如果就一個樹,那么這個參數就沒什么多大的作用)。我們可以通過event來確定鼠標在頁面中具體的位置,然后根據node來判斷右鍵菜單的詳細內容和相關的綁定事件。下面是項目中的代碼:
1 // 右鍵菜單功能 2 function zTreeOnRightClick(event, treeId, treeNode) { 3 $('#rightMenu').remove();// 移出之前的右鍵菜單,如果有; 4 if (treeNode) { 5 zTreeObj.selectNode(treeNode); 6 var isEqu = treeNode.isEqu ? true : false, isEquHtml = ""; 7 if (!isEqu) { 8 isEquHtml = "<li id='addDep'>添加部門</li>" 9 + "<li id='addEqu'>添加設備</li>"; 10 } 11 var editName = isEqu ? "修改設備" : "修改部門"; 12 var deleteName = isEqu ? "刪除設備" : "刪除部門"; 13 var html = "<ul id='rightMenu'>" + isEquHtml + "<li id='edit'>" 14 + editName + "</li>" + "<li id='delete'>" + deleteName 15 + "</li>" + +"</ul>"; 16 var menu = $(html).css({ 17 left : event.pageX + 5 + 'px', 18 top : event.pageY + 5 + 'px' 19 }); 20 $('body').append(menu); 21 menuClick();// 給添加的元素綁定事件 22 } 23 }
我這邊的實際情況是看樹上的節點中是否有isEqu屬性。如果含有這個屬性則證明是設備節點,那么就只有修改設備和刪除設備2個功能。如果沒有,那么就證明這個是部門或者公司節點,那么就有添加設備,添加部門,刪除設備和刪除部門的功能。然后通過jquery的css函數來確定菜單彈出的具體位置。其他的css可以提前在頁面中寫好,比如說hover事件和菜單的樣式。在代碼中只要控制菜單的left和top屬性就行了。這里值得一提的是,我們給菜單綁定的事件menuClick函數每次都需要在菜單添加的時候運行而不是在$(function(){})中,因為這里的菜單本身是不存在body中的,是右鍵點擊的時候動態生成的,然后點擊以后又移除了,所以每次生成的時候都需要給這個菜單綁定相關的點擊事件。詳細的點擊事件這里就不多展開敘述了。
接下來是拖拽事件。值得一提的是這個beforeDrag和beforeDrop這兩個幾戶一模一樣的回調函數,當時沒注意被搞懵逼了。beforeDrag是拖拽前調用的,beforeDrop是拖拽結束前調用的回調。其原理就是鼠標的mousedown和mouseup還有一個dragflag(拖拽的標志)。我這里總公司這個節點是不能移動的,所以在beforeDrap回調里面判斷一下節點的id,如果是0就代表是總公司,在beforeDrag中返回false就不會再調用onDrag函數了,節點就不能被拖拽。下面是項目中的代碼供參考
function zTreeBeforeDrag(treeId, treeNodes) { if (treeNodes[0].id == 0) { layer.msg('總公司目錄無法移動!', { time : 1000 }); return false; } else { return true; } }
這里onDrop回調調用后會自動把移動的節點move到你想要移動的地方。但是我這里需要加一個是否移動的提示框,所以如果還是用onDrop的話,會直接移動。因為我這里的彈窗是異步的,js還是會自己執行下去調用onDrop而不管beforeDrop中返回的,除非調用的是系統的comfirm函數,這個會阻塞js進程,但是樣式不好調我就放棄了,我這里是直接在onDrop中return掉,不讓他移動節點,而是在beforeDrop中自己判斷節點是否可以移動,然后調用ztree的moveNode方法自己移動節點。下面是相關代碼
1 // 拖拽子節點判斷 2 function canInner(treeId, treeNodes, targetNode) { 3 return (targetNode && !targetNode.isEqu); 4 } 5 // 拖拽前的判斷 6 function zTreeBeforeDrop(treeId, treeNodes, targetNode, moveType) { 7 var msg = '是否將 [' + treeNodes[0].sname + '] 移動到 [' + targetNode.sname; 8 switch (moveType) { 9 case 'inner': 10 msg += ' ]之內?'; 11 break; 12 case 'prev': 13 msg += ' ]之前?'; 14 break; 15 case 'next': 16 msg += ' ]之后?'; 17 default: 18 break; 19 } 20 layer.confirm(msg, function(index) { 21 zTreeObj.moveNode(targetNode, treeNodes[0], moveType); 22 layer.close(index); 23 }); 24 return false; 25 } 26 // 拖拽結束 27 function zTreeOnDrop(event, treeId, treeNodes, targetNode, moveType) { 28 if (!targetNode) { 29 layer.msg('目標對象無效!', { 30 time : 1000 31 }); 32 return; 33 } 34 }
上面代碼僅僅用onDrop函數來提示用戶移動到的節點是無效的這個功能而已,其他功能都是在beforeDrop中實現的。到這里忘記介紹了nodes這個屬性。我們一般會在setting.data中啟用simpleData,這樣的話我們可以直接設置id和pid2個參數來確定上下級的關系,而不需要嵌套用children這個屬性來確定上下級的關系,這樣的話后台返回的數據就直接從數據庫中取出返回一個List的類型就行而不需要轉化成復雜的嵌套模式,這個還是挺好用的。下面是我用到的展示的nodes:
1 var zNodes = [ { 2 sname : '總公司', 3 id : 0, 4 pId : -1, 5 open : true, 6 isParent : true 7 }, { 8 sname : '技術中心', 9 id : 1, 10 pId : 0, 11 open : true, 12 isParent : true 13 }, { 14 sname : '生產中心', 15 id : 2, 16 pId : 0, 17 open : true, 18 isParent : true 19 }, { 20 sname : '物流中心', 21 id : 3, 22 pId : 0, 23 open : true, 24 isParent : true 25 }, { 26 sname : '設備1', 27 id : 4, 28 pId : 1, 29 isEqu : true, 30 31 }, { 32 sname : '設備2', 33 id : 5, 34 pId : 1, 35 isEqu : true, 36 37 }, { 38 sname : '設備3', 39 id : 6, 40 pId : 2, 41 isEqu : true, 42 }, { 43 sname : '設備4', 44 id : 7, 45 pId : 3, 46 isEqu : true, 47 }, ];
今天這里的記錄就差不多到這里了,具體的api還是可以參考官網的。而且官網的教程也很詳細,這里就不多介紹了,哈哈(真的不是我懶哦)~