人员选择树,搜索自动筛选功能 (vue+chosen+zTree)

news/2024/11/9 14:07:03

要实现的功能截图:
这里写图片描述

要求:
1、点击收件人输入框可以根据拼音自动筛选数据,并且标记已经选择的数据,没有结果的时候提示,相应的更新左边树节点状态
2、勾选树右侧树的节点左侧输入框出现一一对应的节点名称

用到的插件
vue+chosen+ztree
vue:组件化的MVVM库
chosen:基于jquery的单选列表和多选列表增强插件
ztree:基于jquery的树插件

分析
chosen插件已经可以实现要求1中的大部分效果,我们只需要预先提供chosen需要的数据,通过输入框值的变化实现左右两侧数据一 一对应,最后点击发送获取最终的数据集合ID

具体实现:
一、左侧选择数据,右侧树节点更新
chosen需要的html结构

//只需要提供包含数据的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为:

//基于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值的变化来勾选右侧树的节点

$('select.chosen-select').on('change', function(){
    // 用户改变了选择,快快处理
});

我们同样要写到Vue.nextTick中,其中涉及到树的操作请参照zTree API

//延迟初始化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中的效果我们就全部实现了。

二、勾选树节点,左侧输入框数据更新

//树的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"
            }
        ]
    }
]

文章来源:我的博客


http://www.niftyadmin.cn/n/2043177.html

相关文章

从零开始学安全(四十)●上传文件MIME类型绕过漏洞防御

MIME检测原理 服务端MIME类型检测是通过检查http包的Content-Type字段中的值来判断上传文件是否合法的。 php示例代码&#xff1a; if($_FILES[userfile][type] ! "image/gif") { //检测Content-type //当上传文件的type不为image/gif时&#xff0c;程序不执行文件保…

linux查看CPU性能及工作状态的指令mpstat,vmstat,iostat,sar,top

衡量CPU性能的指标&#xff1a;1&#xff0c;用户使用CPU的情况&#xff1b;CPU运行常规用户进程CPU运行niced processCPU运行实时进程2&#xff0c;系统使用CPU情况&#xff1b;用于I/O管理&#xff1a;中断和驱动用于内存管理&#xff1a;页面交换用户进程管理&#xff1a;进…

Codeforces Round #549 (Div. 2) Solution

传送门 A.The Doors 看懂题目就会写的题 给一个 $01$ 序列&#xff0c;找到最早的位置使得 $0$ 或 $1$ 已经全部出现 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typede…

基于jsp+ssm的火车飞机订票系统

随着旅游业的逐渐的成熟发达&#xff0c;火车客运量大幅度的提高&#xff0c;国内国际的旅游车次的增加&#xff0c;这些都对火车站的信息管理系统提出了更高的要求&#xff0c;所以要不断的完善更新火车票订票系统&#xff0c;提高火车票订票系统的工作效率。 火车票订票系统…

《程序设计入门——C语言》翁恺老师 第四周编程练习记录

1奇偶个数&#xff08;5分&#xff09;题目内容&#xff1a; 你的程序要读入一系列正整数数据&#xff0c;输入-1表示输入结束&#xff0c;-1本身不是输入的数据。程序输出读到的数据中的奇数和偶数的个数。 输入格式: 一系列正整数&#xff0c;整数的范围是&#xff08;0,1000…

javaWeb项目中如何实现在线查看pdf文件

最近有需求要实现在网页直接查看pdf&#xff0c;word&#xff0c;excel文件。但是实际当中并没有很好的开源插件供我们使用&#xff0c;确实有一些付费的插件不错&#xff0c;也很好用&#xff0c;但是对于我来说都不适合。 现在只是单纯的找到了围魏救赵的方法。 就是先实现显…

Java+MySQL 基于Springboot的垃圾分类网站

当前全球都在提倡环境保护&#xff0c;现在社会高速发展&#xff0c;我们每个人每天都会产生很多的垃圾&#xff0c;尤其是工业发展到一定阶段之后这些垃圾的种类也越来越多&#xff0c;如果随意丢弃很可能会造成环境污染&#xff0c;尤其是一些电池等重污染垃圾&#xff0c;所…

byte转bit

由于项目需要&#xff0c;传过来的数据是高位到低位的Byte&#xff0c;需要输出低位到高位的bool数组。 public static bool[] getBits(byte[] byt){bool[] ret new bool[byt.Length * 8];for (int j byt.Length - 1; j > 0; j--){for (int i 0; i < 8; i){ret[(byt.L…