//2018-01-05 基于jquery的树形结构图
function Tree(options){
var opts = $.extend({
node : null,
data : null,
dataType : 'json',
type : 'get',
callback : null,
createBack : null,
clickBack : null
},options);
this.node = opts.node;
this.orgData = opts.data;
this.dataType = opts.dataType;
this.type = opts.type;
this.data = $.extend(true,[],opts.data);
this.createBack = opts.createBack;
this.clickBack = opts.clickBack;
this.callback = opts.callback;
this.hang = false;
};
Tree.prototype = {
constructor : Tree,
trigger : function(){
var _this = this;
if(!_this.node || !_this.node.length || !_this.data){return}
_this.initData(_this.data);
},
//初始化数据
initData:function(data,parent){
var _this = this;
for(var i = 0,len = data.length; i < len; i++){
var curData = data[i];
//curData.id += + new Date();
//设置父级
if(parent){
curData.parent = parent;
}
//设置路由
_this.setRoute(curData,i);
//创建dom
_this.createDom(curData);
//是否存在子集
if(curData.children){
_this.initData(curData.children,curData);
}
}
},
//创建dom
createDom : function(data){
var _this = this;
var html = [];
var level = data.route.split('-').length;
html.push("<div class='group-panel' data-node='group' id='" + data.id + "' data-route='" + data.route + "'>");
html.push("<div class='text-panel " + "level-" + level + "' data-node='txt'>");
html.push("<span title='" + data.txt + "'>"+ data.txt +"</span>");
html.push("<b class='x-line vo-null'>y</b>");
html.push("<a href='javascript:;' data-node='btn' class='btn vo-null'>按钮</a>");
html.push("</div>");
html.push("<div class='children-panel " + "level-" + level + "' data-node='children'></div>");
html.push("<div class='operate-panel'>");
html.push("<b class='y-line vo-null'>y</b>");
html.push("</div>");
html.push("</div>");
var dom = $(html.join(''));
if(typeof _this.createBack == 'function'){
_this.createBack.call(dom.get(0),data);
};
//是否隐藏分支
if(!data.children){
dom.children("[data-node='txt']").find("[data-node='btn']").hide();
}
//插入
if(!data.parent){
_this.node.append(dom);
}else{
$('#' + data.parent.id).children("[data-node='children']").append(dom);
$('#' + data.parent.id).children("[data-node='txt']").find("[data-node='btn']").show();
}
//绑定点击事件
_this.bindClickEve(dom);
},
//设置路由
setRoute : function(data,index){
data.index = index;
if(!data.parent){
data.route = '' + index;
return;
}
var route = '',
parent = data.parent;
while(parent){
route = parent.index + '-' + route;
parent = parent.parent;
}
route = route + index;
data.route = route;
},
//获取当前data
getCurData : function(route){
var _this = this;
var data = null;
for(var i = 0,len = route.length; i < len; i++){
data = data ? data.children[route[i]] : _this.data[route[i]];
}
return data;
},
//点击文本
handleClickTxt : function(){
var _this = this;
return function(){
var $this = $(this);
var $parent = $this.parents("[data-node='group']").eq(0);
var route = $parent.attr('data-route').split('-'),
id = $parent.attr('id');
//查询原始数据
var curData = _this.getCurData(route);
//校验数据
if(!curData || (curData.id + '') != id){
alert('查询错误');
return false;
}
//是否为跳转连接
if(curData.link){
window.location.href = curData.link;
return false;
}
//判断是否为展开状态
var isVisible = $parent.children("[data-node='children']").is(':visible');
//展开点击的回调
if(!isVisible && typeof _this.clickBack == 'function'){
_this.clickBack.call($parent.get(0),curData);
}
//是否请求异步数据
if(curData.asyn){
_this.handleAjax(curData);
}
//判断是否展开
var node = $('#' + curData.id);
if(isVisible){
_this.handleClose(node);
}else{
_this.handleSelected(route);
}
//设置选中
return false;
};
},
//选中
handleSelected : function(route){
var _this = this;
var data = null;
_this.node.find('.on').removeClass('on');
for(var i = 0,len = route.length; i < len; i++){
data = data ? data.children[route[i]] : _this.data[route[i]];
//关闭同级
var siblings = $('#' + data.id).siblings();
_this.handleClose(siblings);
if(i == len - 1){
var node = $('#' + data.id);
if(data.children){
_this.handleOpen(node);
}
node.children("[data-node='txt']").addClass('on');
}
}
},
//绑定点击事件
bindClickEve : function(node){
var _this = this;
node.find("[data-node='txt']").on('click',_this.handleClickTxt());
},
//ajax
handleAjax : function(parent){
var _this = this;
//挂起状态或者已存在子集不发送请求
if(_this.hang || parent.children){return}
_this.hang = true;
$.ajax({
url : parent.asyn + '?id=' + parent.id,
type : _this.type,
dataType : _this.dataType,
data : _this.node.serialize(),
success : function(rdata){
if(typeof _this.callback == 'function'){
_this.callback.call(_this,parent,rdata);
}
_this.hang = false;
},
error : function(){
_this.hang = false;
}
});
},
//展开
handleOpen :function(node){
if(!node || !node.length){return}
if(node.children("[data-node='children']").is(':visible')){
return;
}
node.children("[data-node='children']").show(300);
node.children("[data-node='txt']").addClass('open');
},
//关闭
handleClose : function(node){
if(!node || !node.length){return}
if(!node.children("[data-node='children']").is(':visible')){
return;
}
node.find("[data-node='children']").hide(300);
node.find("[data-node='txt']").removeClass('open');
}
};
//******针对jquery拓展******
$.fn.tree = function(options){
if(!$(this).length){return}
var opts = $.extend({
data : null,
dataType : 'json',
type : 'get',
createBack : null,
clickBack : null,
callback : null
},options);
if(!opts.data){return}
//循环实例化
$(this).each(function(){
new Tree({
node : $(this),
dataType : opts.dataType,
type : opts.type,
data : opts.data,
createBack : opts.createBack,
clickBack : opts.clickBack,
callback : opts.callback
}).trigger();
});
};
sCss:
.vo-tree{
width: 220px;
height: 500px;
overflow: auto;
.group-panel{
position: relative;
.text-panel{
display: block;
background: #ffffff;
width: 80px;
height: 24px;
line-height: 24px;
color: #999;
margin: 0 0 5px;
font-size: 14px;
position: relative;
z-index: 10;
span{
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
.x-line{
position: absolute;
left: -15px;
top: 50%;
height: 1px;
width: 12px;
background: url(../../../image/virgo/tree-line.png) 0 0 repeat-x;
}
.btn{
position: absolute;
left: -20px;
top: 50%;
width: 9px;
height: 9px;
margin: -4px 0 0;
background: url(../../../image/virgo/tree-icon.png) 0 0 repeat-y;
}
&.open{
.btn{
background-position: -18px 0;
}
}
&.level-1{
width: 218px;
height: 70px;
line-height: 70px;
border: 1px solid #ececec;
text-indent: 3em;
font-size: 16px;
.x-line{
display: none;
}
}
&.level-2{
width: 198px;
height: 36px;
line-height: 36px;
background: #91b0c4;
text-indent: 2em;
color: #ffffff;
font-size: 16px;
}
&:hover{
text-decoration: underline;
}
}
.children-panel{
padding: 5px 0 0;
margin: -5px 0 0 20px;
display: none;
}
.operate-panel{
.y-line{
position: absolute;
left: 4px;
top: 0px;
height: 100%;
width: 1px;
background: url(../../../image/virgo/tree-line.png) 0 0 repeat-y;
}
}
}
}
使用:
<div class="vo-tree"></div>
<script type="text/javascript">
var data = [
{
id : 1,
name : 'aaa',
txt : '标题1',
asyn : '../request/tree.json',
children:[
{
id : 11,
name : 'aaa',
txt : '标题1',
asyn : '../request/tree.json',
children:[
{
id : 12,
name : 'aaa',
txt : '标题1',
asyn : '../request/tree.json',
children:[
{
id : 13,
name : 'aaa',
txt : '标题1'
},
{
id : 23,
name : 'bbb',
txt : '标题2'
},
{
id : 33,
name : 'ddd',
txt : '标题3'
}
]
},
{
id : 22,
name : 'bbb',
txt : '标题2',
asyn : '../request/tree.json'
},
{
id : 32,
name : 'ddd',
txt : '标题3',
asyn : '../request/tree.json'
}
]
},
{
id : 21,
name : 'bbb',
txt : '标题2',
asyn : '../request/tree.json'
},
{
id : 31,
name : 'ddd',
txt : '标题3',
asyn : '../request/tree.json'
}
]
},
{
id : 2,
name : 'bbb',
txt : '标题2',
asyn : '../request/tree.json'
},
{
id : 3,
name : 'ddd',
txt : '标题3',
asyn : '../request/tree.json'
}
]
//调用
$(".vo-tree").tree({
data : data,
createBack : function(data){
//创建完成回调
console.log('创建完成回调')
console.log(this)
console.log(data)
},
clickBack : function(data){
//点击回调
console.log('点击回调')
console.log(this);
console.log(data);
},
callback : function(parent,rdata){
var _this = this;
parent.children = rdata.data;
//初始化数据
_this.initData(rdata.data,parent);
//执行打开
_this.handleOpen($('#' + parent.id));
}
});
</script>