要实现的功能截图:php
要求:
一、点击收件人输入框能够根据拼音自动筛选数据,而且标记已经选择的数据,没有结果的时候提示,相应的更新左边树节点状态
二、勾选树右侧树的节点左侧输入框出现一一对应的节点名称html
用到的插件
vue+chosen+ztree
vue:组件化的MVVM库
chosen:基于jquery的单选列表和多选列表加强插件
ztree:基于jquery的树插件vue
分析
chosen插件已经能够实现要求1中的大部分效果,咱们只须要预先提供chosen须要的数据,经过输入框值的变化实现左右两侧数据一 一对应,最后点击发送获取最终的数据集合IDnode
具体实现:
1、左侧选择数据,右侧树节点更新
chosen须要的html结构jquery
//只须要提供包含数据的select标签便可,该select默认隐藏,chosen依据该数据构建新的html结构 <select name="dept" style="width:150px;" id="dept" class="dept_select" multiple="multiple"> //loop start <option value="部门1">部门1</option> <option value="部门2">部门2</option> <option value="部门3">部门3</option> //loop end </select> //chosen初始化 $(function(){ $('.dept_select').chosen({ no_results_text:'没有结果', allow_single_deselect:true }); });
这样要求1中的大部分效果就实现了,option里面的数据咱们须要经过接口从后台获取,这里采用vue解析数据,相应的html结构和js为:ajax
//基于vue解析的html结构 <select data-placeholder="选择发件人" class="chosen-select form-control" tabindex="-1" multiple="multiple"> <template v-for='key in zmailTree'> <option v-for='item in key.userList' value='{{item.id}}'>{{item.name}}</option> </template> </select> //vue实例 var zmailForm=new Vue({ el:'#zmail-form', ready:function(){ var that=this; var getToken=$.cookie('dcValidate'); $.ajax({ type:'get', async:false, url:'后台数据接口地址', dataType: "json", success: function(msg){ that.$set('zmailTree', msg); } }); }, data:{ zmailTree:[] } }); //总结:经过vue获取后台数据,将json数据赋值给zmailTree这个数组,它是含有层级结构的,咱们不须要输出层级结构,只须要输出里面的人员就好了,可是实践中发现一我的问题,数据解析了,鼠标点击输入框出现的下拉列表中并无出现咱们刚才解析出来的数据,咱们须要VUE的Vue.nextTick方法,延迟回调chosen初始化代码: //延迟初始化chosen Vue.nextTick(function () { $('#zmail-select').chosen({ no_results_text: '没有找到该结果',// 当检索时没有找到匹配项时显示的提示文本 search_contains: true //从任意位置开始检索 }); });
而后出现了下面的效果:
接下来咱们要作的就是勾选与左侧选择的数据相对应的节点。chosen提供了一个change方法,该方法当选择的值发生改变时触发,有这个方法咱们就很容易根据select值的变化来勾选右侧树的节点json
$('select.chosen-select').on('change', function(){ // 用户改变了选择,快快处理 });
咱们一样要写到Vue.nextTick中,其中涉及到树的操做请参照zTree APIapi
//延迟初始化chosen Vue.nextTick(function () { $('#zmail-select').chosen({ no_results_text: '没有找到该结果',// 当检索时没有找到匹配项时显示的提示文本 search_contains: true //从任意位置开始检索 }); $('#zmail-select').on('change', function(){ //用户改变了值以后做以下处理 var treeObj = $.fn.zTree.getZTreeObj("zmail-tree");//获取目标容器 treeObj.expandAll(true);//展开全部树节点 treeObj.checkAllNodes(false);//清空全部树节点 $("#zmail-select option:selected").each(function(i,obj){//循环选择出来的数据 //根据节点数据的ID属性搜索,获取条件彻底匹配的节点数据,注:option中解析的是ID var node = treeObj.getNodeByParam("id", obj.value, null); //将选出的节点所有勾选 treeObj.checkNode(node, true, true); }); }); }); //总结:输入框的值只要发生了改变option的状态就会自动更新,咱们根据已选中的option的value(即ID),加上ztree已有的getNodeByParam方法来获取与左侧数据ID一一对应的树中的节点,而后经过checkNode方法勾选这些节点
到这里要求1中的效果咱们就所有实现了。数组
2、勾选树节点,左侧输入框数据更新服务器
//树的html结构,不要忘记写ztree这个class,不然不显示数据 <ul class="ztree" id="zmail-tree"> </ul>
//--------树初始化代码js----------- //人员树基本设置 var zmailTreeSet={ view:{ dblClickExpand:false }, async:{ enable:true, type:'get', url:'服务器数据地址', }, data:{ simpleData:{ enable:true, idKey:'id', pIdKey:'parentId' }, key:{ children:'userList' } }, check:{ enable:true, chkboxType:{'Y':'s','N':'s'} }, callback:{ onCheck:zmailCheck } }; //勾选节点以后要处理的回调函数 function zmailCheck(){ } //初始化人员树 $.fn.zTree.init($('#zmail-tree'),zmailTreeSet);
zmailCheck方法中实现的思路
(1)首先获取点击复选框的节点
var zmaObj = $.fn.zTree.getZTreeObj(treeId);//getZTreeObj插件方法,获取目标ID var zmaNodes = zmaObj.getCheckedNodes(true);//getCheckedNodes获取输入框被勾选的节点集合
(2)其次清空select中的选中状态,将其恢复到初始状态,
$("#zmail-select option").each(function(j,obj){ obj.selected=''; });
(3)根据勾选的节点集合使select中的相应option选中,此处判断的关键是数据id
for(var i = 0;i < zmaNodes.length; i++){ if(typeof(zmaNodes[i].userList) == 'undefined'){//若是该节点的userList属性为空说明不是父节点,存取它的值,若是不为空则跳过 $("#zmail-select option[value="+zmaNodes[i].id+"]").prop('selected','selected'); } }
(4)更新select option列表
//循环外更新select列表 $("#zmail-select").trigger('chosen:updated');
完整的zmailCheck()代码为:
function zmailCheck(){ var zmaObj = $.fn.zTree.getZTreeObj(treeId); var zmaNodes = zmaObj.getCheckedNodes(true); $("#zmail-select option").each(function(j,obj){ obj.selected=''; }); for(var i = 0;i < zmaNodes.length; i++){ if(typeof(zmaNodes[i].userList) == 'undefined'){ $("#zmail-select option[value="+zmaNodes[i].id+"]")[0].selected='selected'; } } $("#zmail-select").trigger('chosen:updated'); }
至此要求2的效果咱们也实现了。
总结
这个功能的完成离不开对zTree和chosen这两个插件的熟练使用,chosen用到的API为change方法、chosen:updated方法,ztree用到的方法为:getNodeByParam(),checkNode(),getCheckedNodes(),checkAllNodes(),expandAll()。
实现左侧=》右侧功能关键点:选出option的selected状态id,经过getNodeByParam()获取含有该ID的全部节点,而后使用checkNode()使这些节点的状态变为选中;
右侧=》左侧实现的关键点:经过getCheckedNodes()获取全部选中的节点,根据选中的节点ID使左侧的select下的option selected状态变为true,循环结束后('chosen:updated')更新option列表。
这个功能还有不完美的地方,那就是获取后台数据那里,我说事后台数据是有层级的,我如今只循环了两次,只取出了二级列表,若是层级有三级四级五级那获取的仍是二级列表,vue我也刚开始学,不知道循环后台数据那里如何一劳永逸的获取不带层级的全部后续动态添加的子级列表。
为了便于讨论给你们看下我从后台获取的json数据:
[ { "id": "20160912113609940493862810692577", "name": "xx公司", "parentId": "0", "userList": [ { "id": "20160912113613185306623590148664", "name": "演示账号" }, { "id": "20160912113613154939672576045528", "name": "成员1" }, { "id": "20160919121104625924937109002003", "name": "成员2" } ] }, { "id": "20160912113611625082971312564873", "name": "组1", "parentId": "20160912113609940493862810692577", "userList": [ { "id": "20160912113613138161662196502779", "name": "成员1" }, { "id": "20160912113613044493434182821910", "name": "成员2" }, { "id": "20160912113613169436263538841431", "name": "成员3" }, { "id": "20160912113613169255388288458627", "name": "成员4" }, { "id": "20160912113613185135119969199907", "name": "成员5" } ] }, { "id": "20160912113611625563131574216031", "name": "组2", "parentId": "20160912113609940493862810692577", "userList": [ { "id": "20160912113613044536244270423866", "name": "成员1" }, { "id": "20160912113613044570977235101231", "name": "成员2" }, { "id": "20160912113613044945364721175243", "name": "成员3" }, { "id": "20160912113613138666099077077505", "mobileNum": "00010656364", "name": "成员4" }, { "id": "20160912113613154114377983132349", "name": "成员5" }, { "id": "20160912113613169433129887352698", "mobileNum": "000610919", "name": "成员6" }, { "id": "20160912113613169883649070173455", "name": "成员7" }, { "id": "20160912113613185006644025528363", "name": "成员8" }, { "id": "20160912113613185400355507045112", "name": "成员9" } ] }, { "id": "20160919115007372634170390528661", "name": "组3", "parentId": "20160912113609940493862810692577", "userList": [ { "id": "20160914151121249285889869855783", "name": "成员1" }, { "id": "20160912113613060689705413198400", "name": "成员2" }, { "id": "20160912113613060223674583460143", "name": "成员3" }, { "id": "20160912113613154692470389028360", "mobileNum": "00093049532", "name": "成员4" } ] } ]
文章来源:个人博客