最近公司要求作一个关于后台的管理系统。在这个mvvm模式横行的年代,虽然这里用jquery作项目可能有点不符合时代的潮流,可是管他呢,能作出来先在说呗(公司之后要改用angular或者vue来统一前端的制做方式),我的以为jquery还挺好用的。废话这里就很少叙述了。下面就先来一张完成后的图片展现一下ztree能够完成的功能。php
额····这边弹出层的阴影是录制软件的问题(这边的前端插件用的是layui,想用的小伙伴能够自行百度layui,顺便一提,我这里用的版本是layui 1.0的,如今layui已经更新到2.0版本了,已经有自适应功能了,挺好用的。你问我为何不用bootstrap?其实这个项目中UI小伙伴给个人时候插件用的是bootstrap,可是本人就先入为主了,仍是以为layui轻便好用,看我的喜爱吧)。css
忘记了初衷这里是来介绍ztree的,好了,下面先来介绍下ztree的基本信息。html
使用ztree的时候能够参考官网的教程来一步步跟着作。zTree官网。详细的api能够参照着官网来看。前端
先看ztree的初始化过程:vue
1 zTreeObj = $.fn.zTree.init($obj, setting, nodes);
这是就是初始加载ztree树。第一个参数$obj表明的是你须要加载ztree的容器。通常默认是一个div。第二个参数是咱们的配置项。下面会详细介绍,第三个nodes就是咱们须要显示的数据,实际项目中通常都是后台返回的json.node
上面展现的功能用到了树的左键点击,邮件点击,拖拽3个大的功能点。这里是我项目中写的setting的内容jquery
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来判断右键菜单的详细内容和相关的绑定事件。下面是项目中的代码:json
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中的,是右键点击的时候动态生成的,而后点击之后又移除了,因此每次生成的时候都须要给这个菜单绑定相关的点击事件。详细的点击事件这里就很少展开叙述了。bootstrap
接下来是拖拽事件。值得一提的是这个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仍是能够参考官网的。并且官网的教程也很详细,这里就很少介绍了,哈哈(真的不是我懒哦)~