bootstrap-treeview树节点实现动态加载(懒加载)

        bootstrap-treeview是一款非常不错的树组件,但是官方提供的版本中只有静态的,也就是说我们在使用的时候必须一次性从服务端查询出所有节点,包括所有根节点和叶节点。如果是简单的数据这样是非常方便的,但在企业级项目中,往往树节点既多又深,一次性全部加载的话不但会影响性能,而且会导致数据不同步。故而,笔者在官方提供的版本的基础上,开发了懒加载功能,下面先来看看实现后的效果。

VID_20231222_143530

        可以看到每点展开一次根节点,右侧就会访问一次服务端,动态加载出其下的子节点,这样可以大大提高性能,还能防止由于不同步造成的数据不准确问题。下面附上重点代码,也是懒加载的核心代码:

/**
 * 类功能描述: 该组件是bootstrap_treeview.js的扩展组件,所以要使用该组件,必须同时引入bootstrap_treeview.js。该组件提供单个树和多个树的异步加载功能。
 * @author 西山水壶
 * 
 * 	一、单个树使用说明
 * 
 * 	1、直接使用前台数据作为节点,不访问后台,代码如下:
 * 	var defaultData = [
 *	    {
 *	        text: 'Parent 1',
 *	        nodes: [
 *	            {
 *	                text: 'Child 1',
 *	                nodes: [
 *	                    {
 *	                        text: 'Grandchild 1',
 *	                    },
 *	                    {
 *	                        text: 'Grandchild 2',
 *	                    }
 *	                ]
 *	            },
 *	            {
 *	                text: 'Child 2',
 *	            }
 *	        ]
 *	    },
 *	    {
 *	        text: 'Parent 2',
 *	    },
 *	    {
 *	        text: 'Parent 3',
 *	    }
 *	];
 *
 *	$('#treeview1').treeview({
 *       data: defaultData
 *  });
 * 
 * 	以上代码defaultData是树的节点数据,treeview1是页面中的div。
 * 
 * 	2、使用单个表的后台数据作为节点,并且该表中能通过父ID字段体现树的层级关系,点击某个父节点时异步加载子节点,代码如下:
 * 
 * 	Bhl.plugin.BootStrapTree.initTree({
 * 
 *		treeViewId			:	"indexsys_zbjk_treeview",	//展示树的页面id
 *		
 *		tableName			:	"BI_ECO_INDEX_SYS_COL",		//存放树节点的数据库表名
 *		
 *		idFieldName			:	"ID_",						//id字段名
 *		
 *		parentIdFieldName	:	"PID_",						//父Id字段名
 *		
 *		codeFieldName		:	"CODE_",					//code字段名(非必须)
 *		
 *		nameFieldName		:	"NAME_",					//树节点文本字段名
 *		
 *		otherFieldName		:	"TYPE_,FUN_",				//其它字段名(非必须)
 *		
 *		orderBySql			:	" ORDER BY CODE_ ",			//排序条件(非必须)
 *		
 *		filterParamRoot		:	{							//该参数为初始化树的根节点时的查询过滤条件(非必须)
 *			searchCondition:"以and开头的sql条件语句"				//searchCondition属性名是组件默认的,不能更改
 *		},
 *		
 *		filterParamChildren	:	{							//该参数为展开树的根节点加载子节点时的查询过滤条件(非必须)
 *	 		searchConditionByExpand:"以and开头的sql条件语句"		//searchConditionByExpand属性名是组件默认的,不能更改
 *		}
 * 	});
 * 
 * 	以上代码为初始化该扩展组件属性的代码,其中所有属性都不是官方提供的,并且每个属性的值只是假设值,实际操作中要替换成自己需要的值,后台的Controller和Adapter都使用系统默认的,
 * 	执行上面的代码后并不能展示树,要展示树还要执行以下代码:
 * 
 * 	var param={
 * 
 * 		multiSelect					:	false,						//是否可以多选
 * 
 *		onNodeSelected				: 	function(event, node) {		//选中树节点触发的事件
 *			do something;
 *	    },
 *	    
 *	    onNodeUnselected			: 	function(event, node) {		//取消选中树节点触发的事件
 *	    	do something;
 *      },
 *        
 *      showCheckboxOnlyChildren	: 	false,						//是否只在子节点显示复选框(非官方)
 *      
 *      showCheckboxCondition		:	function(node){				//满足一定条件才显示复选框,满足返回true,否则返回false(非官方)
 *      	do something;
 *      }
 *        
 *		showCheckbox				: 	true,						//是否显示复选框
 *		
 *      onNodeChecked				: 	function(event, node) {		//选中复选框触发的事件
 *       	do something;
 *      },
 *        
 *      onNodeUnchecked				: 	function(event, node) {		//取消选中复选框触发的事件
 *        	do something;
 *      }
 *	}
 *	
 *	以上代码中的属性为官方提供,只不过这几个是常用的,其他不常用的还有很多,请参看官方手册,其中showCheckboxOnlyChildren属性为非官方的,
 *	是作者后来加到bootstrap_treeview.js中的,原版的bootstrap_treeview.js没有这个属性。
 *	
 *	Bhl.plugin.BootStrapTree.buildTree(param);	//执行这行代码才真正把树显示出来
 *
 *	3、使用自己的Controller作为后台,点击某个父节点时异步加载子节点,代码如下:
 *
 *	Bhl.plugin.BootStrapTree.initTree({
 * 
 *		treeViewId			:	"indexsys_zbjk_treeview",					//展示树的页面id
 *		
 *		jsonUrl				:	"bi/companyinfo/cdes/getGroupTreeJson",		//自己的Controller
 *
 *		filterParamRoot		:	{											//该参数为初始化树的根节点时的查询过滤条件(非必须),里面的属性为自己实际需要的属性
 *			year	:	"2016",
 *			month	:	"05",
 *			其它属性...
 *		},
 *		
 *		filterParamChildren	:	{											//该参数为展开树的根节点加载子节点时的查询过滤条件(非必须)
 *	 		year	:	"2016",
 *			month	:	"05",
 *			其它属性...
 *		},
 *
 *		beforeOnClick		:	function(node){								//展开子节点前触发的事件
 *	    	do something;
 *		}
 * 	});
 * 
 * 	自己的Controller返回的json格式应该是以下格式:
 * 	
 * 	[
 *	    {
 *	        text	: 	'Parent 1',		//要显示的文本
 *			nodes	:	[],				//nodes代表该节点下还有子节点
 *			其他属性...
 *	    },
 *	    {
 *	        text	: 	'Parent 2',
 *			其他属性...
 *	    },
 *	    {
 *	        text	: 	'Parent 3',
 *			其他属性...
 *	    }
 *	]
 *
 *	自己的Controller返回的json应至少包含text属性,一般情况下还应包含id属性,如果该节点下有子节点还应包含nodes属性,但是nodes属性一定是个空数组,在点击时候才加载子节点。
 *	需要注意的是,该组件只允许设置一个Controller,也就是说加载根节点和点击根节点异步加载子节点都使用这个Controller,所以该组件提供了filterParamRoot和
 *	filterParamChildren属性以便于加载不同节点的时候传入不同的过滤参数。但是很多时候需要在展开子节点的时候才能确定传什么参数,比如父id,该组件的beforeOnClick事件能满足
 *	这个需求,例如在点击父节点的时候传入父id,应该按照以下方式设置:
 *
 *	beforeOnClick		:	function(node){								//展开子节点前触发的事件
 *   	Bhl.plugin.BootStrapTree.filterParamChildren={
 *				pid:node.id
 *		}
 *	}
 *
 *	以上代码node为节点对象,pid和node.id在实际使用时应该替换成自己需要的参数
 *
 *
 *	二、多个树使用说明
 *
 *	1、直接使用前台数据作为节点,不访问后台,代码如下:
 * 	var defaultData1 = [
 *	    {
 *	        text: 'Parent 1',
 *	        nodes: [
 *	            {
 *	                text: 'Child 1',
 *	                nodes: [
 *	                    {
 *	                        text: 'Grandchild 1',
 *	                    },
 *	                    {
 *	                        text: 'Grandchild 2',
 *	                    }
 *	                ]
 *	            },
 *	            {
 *	                text: 'Child 2',
 *	            }
 *	        ]
 *	    },
 *	    {
 *	        text: 'Parent 2',
 *	    },
 *	    {
 *	        text: 'Parent 3',
 *	    }
 *	];
 *
 *	$('#treeview1').treeview({
 *       data: defaultData1
 *  });
 *  
 *  var defaultData2 = [
 *	    {
 *	        text: 'Parent 21',
 *	        nodes: [
 *	            {
 *	                text: 'Child 21',
 *	                nodes: [
 *	                    {
 *	                        text: 'Grandchild 21',
 *	                    },
 *	                    {
 *	                        text: 'Grandchild 22',
 *	                    }
 *	                ]
 *	            },
 *	            {
 *	                text: 'Child 22',
 *	            }
 *	        ]
 *	    },
 *	    {
 *	        text: 'Parent 22',
 *	    },
 *	    {
 *	        text: 'Parent 23',
 *	    }
 *	];
 *
 *  $('#treeview2').treeview({
 *       data: defaultData2
 *  });
 *  
 *  2、使用单个表的后台数据作为节点,并且该表中能通过父ID字段体现树的层级关系,点击某个父节点时异步加载子节点,代码如下:
 * 
 * 	Bhl.plugin.BootStrapTree.initTree({
 * 
 *		treeViewId			:	["indexsys_zbjk_treeview1","indexsys_zbjk_treeview2"],	//展示树的页面id
 *		
 *		tableName			:	["BI_ECO_INDEX_SYS_COL1","BI_ECO_INDEX_SYS_COL2"],		//存放树节点的数据库表名
 *		
 *		idFieldName			:	["ID1_","ID2_"],										//id字段名
 *		
 *		parentIdFieldName	:	["PID1_","PID2_"],										//父Id字段名
 *		
 *		codeFieldName		:	["CODE1_","CODE2_"],									//code字段名(非必须)
 *		
 *		nameFieldName		:	["NAME1_","NAME2_"],									//树节点文本字段名
 *		
 *		otherFieldName		:	["TYPE1_,FUN1_","TYPE2_,FUN2_"],						//其它字段名(非必须)
 *		
 *		orderBySql			:	["ORDER BY CODE1_","ORDER BY CODE2_"],					//排序条件(非必须)
 *		
 *		filterParamRoot		:	[														//该参数为初始化树的根节点时的查询过滤条件(非必须)
 *			{							
 *				searchCondition:"以and开头的sql条件语句"										//searchCondition属性名是组件默认的,不能更改
 *			},
 *			{							
 *				searchCondition:"以and开头的sql条件语句"										//searchCondition属性名是组件默认的,不能更改
 *			}
 *		],
 *		
 *		filterParamChildren		:	[													//该参数为展开树的根节点加载子节点时的查询过滤条件(非必须)
 *			{							
 *				searchConditionByExpand:"以and开头的sql条件语句"								//searchConditionByExpand属性名是组件默认的,不能更改
 *			},
 *			{							
 *				searchConditionByExpand:"以and开头的sql条件语句"								//searchConditionByExpand属性名是组件默认的,不能更改
 *			}
 *		],
 * 	});
 * 
 * 	以上代码为在同一页面中构建两个树的代码,所有属性都是数组形式,每个属性的顺序一定要统一,除了treeViewId属性外,如果其它属性多个树的值都一样,那么也可以写成非数组形式,例如两个表的ID
 *  字段名一样,那么可以写成如下形式:
 *  
 * 	idFieldName:"ID_"
 * 
 * 	当然也可以写成如下形式:
 * 
 * 	idFieldName:["ID_","ID_"]
 * 
 *  如果根节点过滤参数一样,可以写成如下形式:
 *  
 *  filterParamRoot		:	{							
 *		searchCondition:"以and开头的sql条件语句"				
 *	}
 *	
 *	其它字段以此类推。
 *
 * 	执行上面的代码后并不能展示树,要展示树还要执行以下代码:
 * 
 * 	var param={
 * 
 *		showCheckboxOnlyChildren	: 	[false,true],
 *
 *		showCheckboxCondition		: 	[
 *        
 *          function(node) {
 *            	do something;
 *          },
 *            
 *          function(node) {
 *				do something;
 *          }
 *            
 *      ],
 *
 *		showCheckbox				: 	[false,true],
 *		
 *      onNodeChecked				: 	[
 *        
 *          function(event, node) {
 *            	do something;
 *          },
 *            
 *          function(event, node) {
 *				do something;
 *          }
 *            
 *      ],
 *        
 *      onNodeUnchecked				: 	[
 *        
 *          function(event, node) {
 *            	do something;
 *          },
 *            
 *          function(event, node) {
 *            	do something;
 *          }
 *            
 *      ],
 *        
 *		onNodeSelected				: 	[
 *		
 *		    function(event, node) {
 *				do something;
 *	        },
 *	        
 *	        function(event, node) {
 *	        	do something;
 *          }
 *            
 *	    ],
 *	}
 *
 *	注意:如果是多个树,以上param中的属性必须为数组形式。
 *	
 *	Bhl.plugin.BootStrapTree.buildTree(param);
 *
 *	3、使用自己的Controller作为后台,点击某个父节点时异步加载子节点,代码与上面类似,需要注意的是以下代码:
 *
 *	beforeOnClick		:	[
 *		function(node){								
 *   		Bhl.plugin.BootStrapTree.filterParamChildren[0]={
 *				pid:node.id
 *			}
 *		},
 *		function(node){								
 *   		Bhl.plugin.BootStrapTree.filterParamChildren[1]={
 *				pid:node.id
 *			}
 *		}
 *	]
 *	
 *	以上代码中要注意把Bhl.plugin.BootStrapTree.filterParamChildren写成数组形式,其他函数数组也需要注意。
 */
$.bhl_ns("Bhl.plugin.BootStrapTree",function(){
	Bhl.plugin.BootStrapTree={
			
		/**
		 * 项目上下文
		 */
		context:'',
		
		/**
		 * 获取数据的后台
		 */
		jsonUrl:"bi/bootstrap/tree/getTreeJsonData",
		isAsync:0,
		
		/**
		 * 展示树的页面id
		 */
		treeViewId:null,
		
		/**
		 * 左侧导航栏id
		 */
		sidebarId:"frame-main-sidebar",
		
		/**
		 * 鼠标放到树节点上的提示信息
		 */
		reminderDiv:"<div id='bootStrapTree_reminderDiv' style='z-index:999;font-family:\"微软雅黑\";display:none;position:fixed;top:100px;left:300px;background-color:#FFEE99;color:black;'></div>",
		
		/**
		 * 加载节点时的等待信息
		 */
		loadWaitDiv:"<div id='bootStrapTree_loadWaitDiv' style='z-index:999;font-family:\"微软雅黑\";display:none;position:absolute;top:100px;left:300px;background-color:#CCCCFF;'></div>",
		
		/**
		 * 每个节点最多显示的字的个数
		 */
		characterNum:13,
		
		/**
		 * 树的实例
		 */
		treeObj:null,
		
		/**
		 * 获取数据的valueList
		 */
		key:"bi_bootstrap_tree_Adapter",
		
		/**
		 * 存放树节点的数据库表名
		 */
		tableName:null,
		
		/**
		 * id字段名
		 */
		idFieldName:null,
		
		/**
		 * parentId字段名
		 */
		parentIdFieldName:null,
		
		/**
		 * code字段名
		 */
		codeFieldName:null,
		
		/**
		 * 其它字段名
		 */
		otherFieldName:null,
		
		/**
		 * 树节点文本字段名
		 */
		nameFieldName:null,
		
		/**
		 * 根节点的过滤参数
		 */
		filterParamRoot:null,
		
		/**
		 * 子节点的过滤参数
		 */
		filterParamChildren:null,
		
		/**
		 * 排序条件
		 */
		orderBySql:null,
		
		/**
		 * 鼠标点击加号时的x坐标
		 */
		pageX:null,
		
		/**
		 * 鼠标点击加号时的y坐标
		 */
		pageY:null,
		
		/**
		 * 加载子节点后的回调函数
		 */
		getChildrenCallBack:null,
		
		/**
		 * 初始化树
		 */
		initTree:function(data){
			$.extend(true,Bhl.plugin.BootStrapTree,data);
			var me=this;
			if(me.treeViewId.constructor===Array){
				me.jsonUrl=me.initMulityTree(me.jsonUrl);
				me.key=me.initMulityTree(me.key);
				me.tableName=me.initMulityTree(me.tableName);
				me.idFieldName=me.initMulityTree(me.idFieldName);
				me.parentIdFieldName=me.initMulityTree(me.parentIdFieldName);
				me.codeFieldName=me.initMulityTree(me.codeFieldName);
				me.otherFieldName=me.initMulityTree(me.otherFieldName);
				me.nameFieldName=me.initMulityTree(me.nameFieldName);
				me.filterParamChildren=me.initMulityTree(me.filterParamChildren);
				me.filterParamRoot=me.initMulityTree(me.filterParamRoot);
				me.orderBySql=me.initMulityTree(me.orderBySql);
			}
		},
		
		/**
		 * 处理多个树
		 */
		initMulityTree:function(obj){
			var me=this;
			if (obj==null) {
				obj=new Array();
				$.each(me.treeViewId,function(i,treeViewId){
					obj.push(null);
				});
			}else if(obj.constructor!==Array){
				var val=obj;
				obj=new Array();
				$.each(me.treeViewId,function(i,treeViewId){
					obj.push(val);
				});
			}
			return obj;
		},
		
		/**
		 * 获取数据
		 */
		getTreeData:function(param,callBack,async){
			if (!!param.otherFieldName) {
				var otherFieldNames=param.otherFieldName.split(","),
					str="";
				$.each(otherFieldNames,function(i,obj){
					str+="A."+obj+" as "+obj+",";
				});
				param.otherFields=str;
			}
			$.ajax({
				type: "GET",
				async:this.isAsync==1? false :async  ,
				url: '/'+param.jsonUrl,
				data: param,
				beforeSend:function(req){
					var $loadWaitDiv=$(Bhl.plugin.BootStrapTree.loadWaitDiv);
					if ($("#bootStrapTree_loadWaitDiv").length<1) {
						$loadWaitDiv.appendTo($('body'));
					}
					$loadWaitDiv=$("#bootStrapTree_loadWaitDiv");
					$loadWaitDiv.html("&nbsp;&nbsp;正在加载请稍候...&nbsp;&nbsp;");
					$loadWaitDiv.css("top",Bhl.plugin.BootStrapTree.pageY).css("left",Bhl.plugin.BootStrapTree.pageX+20);
					$("#bootStrapTree_loadWaitDiv").show();
				},
				success: callBack,
				error:function(e){
					Bhl.plugin.BootStrapTree.treeObj=null;
				},
				complete:function(){
					$("#bootStrapTree_loadWaitDiv").hide();
				}
			});
		},
		
		/**
		 * 处理节点数据
		 * data 要处理的数据
		 * level 节点所在的层级
		 */
		disposeTreeData:function(data,level){
			//加1是为了保证节点前面有加号的时候不会折行
			var num=Bhl.plugin.BootStrapTree.characterNum-(level==0?0:level+1);
			$.each(data,function(){
				this.level=level;
				if (!!this.value) {
					this.text=this.value;
					if ( this.value&&this.value.length>num ) {
						this.text=this.value;
					}else{
						this.value=null;
					}
				}else{
					if ( this.text&&this.text.length>num ) {
						this.value=this.text;
						this.text=this.value;
					}
				}
				if (!!this.nodes) {
					Bhl.plugin.BootStrapTree.disposeTreeData(this.nodes,level+1);
				}
			});
		},
		
		/**
		 * 注册节点鼠标划过事件
		 */
		registerTreeMouseover:function($treeView,treeObj){
			function move(target, event){
				var $reminderDiv=$(Bhl.plugin.BootStrapTree.reminderDiv);
				var $event=$(target);
				
				if ($("#bootStrapTree_reminderDiv").length<1) {
					$reminderDiv.appendTo($event);
				}
				$reminderDiv=$("#bootStrapTree_reminderDiv");
				
				$reminderDiv.css("top",event.pageY+10).css("left",event.pageX+10);
			}
			
			$treeView.find("li").off('mouseover');
			$treeView.find("li").on('mouseover', $.proxy(function(event){
				var node2=treeObj.findNode($(this));
				if(!!node2.value){
					move($(this), event);
					var $reminderDiv=$("#bootStrapTree_reminderDiv");
					$reminderDiv.html("&nbsp;&nbsp;"+node2.value+"&nbsp;&nbsp;");
					$("#bootStrapTree_reminderDiv").show();
				}
			})).on('mouseout', function(event){
				$("#bootStrapTree_reminderDiv").hide();
				move(this, event);
			}).on('mousemove', function(event){
				move(this, event);
			});
		},
		
		/**
		 * 展开节点之前执行
		 */
		registerSidebarClick:function($treeView,treeObj){
			$("#"+Bhl.plugin.BootStrapTree.sidebarId).on('click', function(event){
				if (!treeObj) {
					return;
				}
				setTimeout(function(){
					if ($treeView.width()<270) {
						Bhl.plugin.BootStrapTree.characterNum=10;
					}else if($treeView.width()<350){
						Bhl.plugin.BootStrapTree.characterNum=13;
					}else if($treeView.width()<450){
						Bhl.plugin.BootStrapTree.characterNum=16;
					}else{
						Bhl.plugin.BootStrapTree.characterNum=20;
					}
					if (!!treeObj) {
						var nodes=treeObj.tree;
						Bhl.plugin.BootStrapTree.disposeTreeData(nodes,0);
						treeObj.render();
						Bhl.plugin.BootStrapTree.registerTreeMouseover($treeView,treeObj);
					}
				},800)
			});
		},
		
		/**
		 * 展开节点之前执行
		 */
		beforeOnClick:function(node){
		},
		
		/**
		 * 查找节点
		 */
		findNodes:function(treeObj,option){
			var nodes=$.grep(treeObj.nodes, function (node) {
				var b=true;
				$.each(option,function(name,value){
					if (node[name]!==value) {
						b=false;
					}
				});
				return b;
			});
			return nodes;
		},
		
		/**
		 * 构建树
		 */
		buildTree:function(treeData,userCallBack){
			if(Bhl.plugin.BootStrapTree.treeViewId.constructor===Array){
				Bhl.plugin.BootStrapTree.treeObj=new Array();
				$.each(Bhl.plugin.BootStrapTree.treeViewId,function(i,treeViewId){
					var $treeView=$('#'+treeViewId),jsonUrl;
					$treeView.empty();
					var param={
						tableName:Bhl.plugin.BootStrapTree.tableName[i],
						idFieldName:Bhl.plugin.BootStrapTree.idFieldName[i],
						parentIdFieldName:Bhl.plugin.BootStrapTree.parentIdFieldName[i],
						nameFieldName:Bhl.plugin.BootStrapTree.nameFieldName[i],
						codeFieldName:Bhl.plugin.BootStrapTree.codeFieldName[i],
						orderBySql:Bhl.plugin.BootStrapTree.orderBySql[i],
						jsonUrl:Bhl.plugin.BootStrapTree.jsonUrl[i],
						otherFieldName:Bhl.plugin.BootStrapTree.otherFieldName[i],
						key:Bhl.plugin.BootStrapTree.key[i],
					};
					var callBack=function(obj){
						Bhl.plugin.BootStrapTree.disposeTreeData(obj.data,0);

						var treeParam={
							levels: 0,
							showBorder: false,
							onClick: function(event) {
								var $target=$(event.target);
								var treeObj=Bhl.plugin.BootStrapTree.treeObj[i];
								if ($target.attr("class").indexOf("expand-icon")>-1) {
									Bhl.plugin.BootStrapTree.pageX=event.pageX;
									Bhl.plugin.BootStrapTree.pageY=event.pageY;
									var node2=treeObj.findNode($target);
									Bhl.plugin.BootStrapTree.beforeOnClick[i](node2);
									if(!!node2.nodes&&node2.nodes.length==0){
										var childParam={
												parentId:node2.id
										}
										$.extend(true,childParam,param);
										var level=$target.prevAll("span[class='indent dd-nodrag']").length+1;
										$.extend(true,childParam,Bhl.plugin.BootStrapTree.filterParamChildren[i]);
										Bhl.plugin.BootStrapTree.getTreeData(childParam,function(obj){
											Bhl.plugin.BootStrapTree.disposeTreeData(obj.data,level);
											$.extend(true,node2.nodes,obj.data)
											treeObj.setInitialStates({ nodes: [node2] }, 0);
											treeObj.clickHandler(event);
											Bhl.plugin.BootStrapTree.registerTreeMouseover($treeView,treeObj);
											if (Bhl.plugin.BootStrapTree.getChildrenCallBack!=null) {
												Bhl.plugin.BootStrapTree.getChildrenCallBack[i].call(this,obj.data);
											}
										},true);
									}else{
										treeObj.clickHandler(event);
									}
									
								}
								else{
									treeObj.clickHandler(event);
								}
								Bhl.plugin.BootStrapTree.registerTreeMouseover($treeView,treeObj);
							},
							data: obj.data
						}
						var p={};
						$.each(treeData,function(name,value){
							p[name]=value[i];
						});
						$.extend(true,treeParam,p);
						$treeView.treeview(treeParam);
						var treeObj=$treeView.data('treeview');
						Bhl.plugin.BootStrapTree.treeObj.push(treeObj);
						$treeView.off('click');
						$treeView.on('click', $.proxy(treeParam.onClick,treeObj));
						Bhl.plugin.BootStrapTree.registerSidebarClick($treeView,treeObj);
						Bhl.plugin.BootStrapTree.registerTreeMouseover($treeView,treeObj);
						
						if (Bhl.plugin.BootStrapTree.getChildrenCallBack!=null) {
							Bhl.plugin.BootStrapTree.getChildrenCallBack[i].call(this,obj.data);
						}
						if($.isFunction(userCallBack)){
							userCallBack.call(this,obj.data);
						}
					}
					var rootParam={
							noParentId:true
					}
					$.extend(true,rootParam,param);
					$.extend(true,rootParam,Bhl.plugin.BootStrapTree.filterParamRoot[i]);
					Bhl.plugin.BootStrapTree.getTreeData(rootParam,callBack,false);
				});
			}else{
				var $treeView=$('#'+Bhl.plugin.BootStrapTree.treeViewId);
				$treeView.empty();
				var param={
					tableName:this.tableName,
					idFieldName:this.idFieldName,
					parentIdFieldName:this.parentIdFieldName,
					nameFieldName:this.nameFieldName,
					codeFieldName:this.codeFieldName,
					jsonUrl:this.jsonUrl,
					otherFieldName:this.otherFieldName,
					orderBySql:this.orderBySql,
					key:this.key
				};
				var callBack=function(obj){
					Bhl.plugin.BootStrapTree.disposeTreeData(obj.data,0);

					var treeParam={
						levels: 0,
						showBorder: false,
						onClick: function(event) {
							var $target=$(event.target);
							if ($target.attr("class").indexOf("expand-icon")>-1) {
								var node2=Bhl.plugin.BootStrapTree.treeObj.findNode($target);
								Bhl.plugin.BootStrapTree.beforeOnClick(node2);
								if(!!node2.nodes&&node2.nodes.length==0){
									var childParam={
											parentId:node2.id
									}
									$.extend(true,childParam,param);
									$.extend(true,childParam,Bhl.plugin.BootStrapTree.filterParamChildren);
									var level=$target.prevAll("span[class='indent dd-nodrag']").length+1;
									Bhl.plugin.BootStrapTree.getTreeData(childParam,function(obj){
										Bhl.plugin.BootStrapTree.disposeTreeData(obj.data,level);
										$.extend(true,node2.nodes,obj.data)
										Bhl.plugin.BootStrapTree.treeObj.setInitialStates({ nodes: [node2] }, 0);
										Bhl.plugin.BootStrapTree.treeObj.clickHandler(event);
										Bhl.plugin.BootStrapTree.registerTreeMouseover($treeView,Bhl.plugin.BootStrapTree.treeObj);
										if (Bhl.plugin.BootStrapTree.getChildrenCallBack!=null) {
											Bhl.plugin.BootStrapTree.getChildrenCallBack.call(this,obj.data);
										}
									},true);
								}else{
									Bhl.plugin.BootStrapTree.treeObj.clickHandler(event);
								}
								
							}
							else{
								Bhl.plugin.BootStrapTree.treeObj.clickHandler(event);
							}
							Bhl.plugin.BootStrapTree.registerTreeMouseover($treeView,Bhl.plugin.BootStrapTree.treeObj);
						},
						data: obj.data
					}
					$.extend(true,treeParam,treeData);
					$treeView.treeview(treeParam);
					Bhl.plugin.BootStrapTree.treeObj=$treeView.data('treeview');
					$treeView.off('click');
					$treeView.on('click', $.proxy(treeParam.onClick, Bhl.plugin.BootStrapTree.treeObj));
					Bhl.plugin.BootStrapTree.registerSidebarClick($treeView,Bhl.plugin.BootStrapTree.treeObj);
					Bhl.plugin.BootStrapTree.registerTreeMouseover($treeView,Bhl.plugin.BootStrapTree.treeObj);
					
					if (Bhl.plugin.BootStrapTree.getChildrenCallBack!=null) {
						Bhl.plugin.BootStrapTree.getChildrenCallBack.call(this,obj.data);
					}
					if($.isFunction(userCallBack)){
						userCallBack.call(this,obj.data);
					}
				}
				var rootParam={
						noParentId:true,
				}
				$.extend(true,rootParam,param);
				$.extend(true,rootParam,this.filterParamRoot);
				this.getTreeData(rootParam,callBack,true);
			}
		}
	}
});

        该代码不但支持单棵树,还支持多棵树,为了大家方便测试,同时附上整个代码包,里面包括所需的js和css文件

链接如下:

https://download.csdn.net/download/leonMary/88652361

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西山水壶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值