ExtJS带复选框的下拉树对复选框中半选状态的实现

Extjs基本组件:带复选框的下拉树javascript

        首先,咱们对于ExtJs实现的带复选框的下拉树应该有一个简单的了解,从下面的例子中能够看出,treepanel是经过节点中checked的值(true,false)来实现复选框的两种状态(勾选,不选)的。css

代码段:java

Ext.create('Ext.window.Window', {
	title: 'Test',
    height: 230,
    width: 400,
    layout: 'fit',
	autoShow:true,
    items: {
        xtype: 'treepanel',
        store: Ext.create('Ext.data.TreeStore', {
		    root: {
		        expanded: true,
		        children: [
		            { text: 'child1', leaf: true, checked: false},
		            { text: 'child2', expanded: true, checked: false, children: [
		                { text: 'child2-1', expanded: true, checked: false, children:[
		                 	{ text: 'child2-1-1', leaf: true, checked: true},
		                 	{ text: 'child2-1-2', leaf: true, checked: false}
		            	] },
		            	{ text: 'child2-2', leaf: true, checked: true}
		            ] },
		            { text: 'child3', leaf: true, checked: false }
		        ]
		    }
		}),
    	rootVisible: false
 	}
});

展现图:node


半选的实现原理app

        其实实现checkbox半选很简单,首先咱们应该知道,显示在界面上的效果不过就是一张图片而已,而checked的值(true/false)就像两个开关同样,随着值得改变,由css样式去更改图片;而咱们如今要作的就是在此基础上再加一个开关(indeterminate),优先级比checked高,当indeterminate = true时,由css样式去更改咱们本身的半选图片,indeterminate = false时,由checked去负责复选框的选中和不选两种状态。ide

        须要注意的一点就是,因为点击半选的复选框时,复选框须要处于不选状态中,因此当复选框处于半选状态时,checked此时应该等于true。ui

       

ok,从上面的原理能够看出咱们实现半选的几个难点:this

  1. 随着checkbox的点击,正确的改变节点中checked和indeterminate的值
  2. 根据checked和indeterminate的值如何修改样式

那么,该怎么解决呢?url

自定义组件code

        组件的自定义封装是Extjs的基本功了,咱们须要封装一个组件来实现咱们上述的难点1

Ext.define('component.CheckTree', {
	extend: 'Ext.tree.Panel',
	requires: [
		'Ext.data.TreeStore'
	],
	xtype: 'checktree',
	store: {},
	rootVisible: false,
	useArrows: true,
	frame: true,
	title: 'Check Tree',
	header: false,
	bufferedRenderer: false,
	animate: true,
	minHeight: 200,
	maxHeight: 200,
	bodyStyle: 'overflow-x:no; overflow-y:auto',
	SELSTATUS: {
		NONE: 0,      //没有选中
		HALFSEL: 1,    //半选
		ALLSEL: 2      //全选
	},

	listeners: {
		checkchange: function(node, checked) {
			this.setChildChecked(node, checked);
			this.setParentChecked(node, checked);
		}
	},

	initComponent: function() {
		Ext.apply(this, {
			store: this.store,
		});
		this.callParent();
	},
	
	//遍历全部子节点,全选或全不选全部子节点,indeterminate设置为false
	setChildChecked: function(node, checked) {
		var me = this;
		node.expand();
		node.set('indeterminate', false);
		node.data.checked = !checked;
		node.set('checked', checked);
		if (node.hasChildNodes()) {
			node.eachChild(function(child) {
				this.setChildChecked(child, checked);
			}, me)
		}
	},
	
	//遍历全部的父节点,设置复选框的三种状态  
    //注意:checked的set方法只有在当前值与要改变的值不一样时,才回去修改样式
	setParentChecked: function(node, checked, selStatus) {
		var me = this,
			parentNode = node.parentNode,
			isHalfSel = false, //半选
			isAllSel = false, //全选
			isNone = true,
			indeterminate,
			checkedArr = [],
			indexT, indexF;
			
		if (parentNode) {
			if(typeof(selStatus) == 'number'){
				switch (selStatus){
					case 0:
						node.set('indeterminate', false);
						node.data.checked = true;
						node.set('checked', false);
						me.setParentChecked(node, checked, null);
						break;
					case 1:
						node.set('indeterminate', true);
						node.data.checked = false;
						node.set('checked', true);
						me.setParentChecked(parentNode, checked, me.SELSTATUS['HALFSEL']);
						break;
					case 2:
						node.set('indeterminate', false);
						node.data.checked = false;
						node.set('checked', true);
						me.setParentChecked(node, checked, null);
						break;
					default:
						break;
				}
			}else{
				selStatus = null;
				parentNode.eachChild(function(childnode) {
					indeterminate = childnode.get('indeterminate');
					if (typeof(indeterminate) == 'boolean' && indeterminate) {
						selStatus = me.SELSTATUS['HALFSEL'];
					}
					if(!isHalfSel){
						checkedArr.push(childnode.get('checked'));
					}
				});
				if(!selStatus){
					indexT = checkedArr.indexOf(true);
					indexF = checkedArr.indexOf(false);
					switch (true){
						case  -1 == indexT:
							selStatus = me.SELSTATUS['NONE'];
							break;
						case  -1 == indexF:
							selStatus = me.SELSTATUS['ALLSEL'];
							break;
						default:
							selStatus = me.SELSTATUS['HALFSEL'];
							break;
					}
				}
				me.setParentChecked(parentNode, checked, selStatus);
			}
		}
	}
});

 

样式的添加与控制

        已经来到了最后一步,黎明的曙光即将到来。

        首先,咱们须要明确几点:

            1.  只有当node.set('checked', true/false),而且node.get('checked')的值与改变的值不一样时,才会去修改样式;

            2.  当复选框为不选状态的时候,checkboxCls = ‘.x-tree-checkbox’ ,当为选中的时候,checkboxCls = ‘.x-tree-checkbox  .x-tree-checkbox-checked’ 

.x-tree-checkbox-checked {
    background-position: 0 -15px;
}

.x-tree-checkbox {
    margin-right: 4px;
    top: 5px;
    width: 15px;
    height: 15px;
    background-image: url(images/form/checkbox.png);
}

            

ok,说了这么多,相信你们的思路应该比较清晰了,经过set方法进入源码,能够发现能够在Ext.tree.Column中的treeRenderer方法添加咱们须要的样式,那么,咱们能够重写这个方法,其中.x-tree-checkbox-indeterminate是咱们实现半选的样式

代码段:

Ext.define('Ext.overrides.tree.Column', {
	override: 'Ext.tree.Column',
	
	treeRenderer: function(value, metaData, record, rowIdx, colIdx, store, view) {
        var me = this,
            cls = record.get('cls'),
            rendererData;
        // The initial render will inject the cls into the TD's attributes.
        // If cls is ever *changed*, then the full rendering path is followed.
        if (metaData && cls) {
            metaData.tdCls += ' ' + cls;
        }
        rendererData = me.initTemplateRendererData(value, metaData, record, rowIdx, colIdx, store, view);
        
        //导航树复选框的半选状态实现
        var indeterminate = record.get('indeterminate');
        if('boolean' === typeof(indeterminate) && indeterminate){
        	rendererData.checkboxCls += ' x-tree-checkbox-indeterminate';
        }
        
        return me.getTpl('cellTpl').apply(rendererData);
    }
});

            

固然,.x-tree-checkbox-indeterminate是不存在的,是咱们本身须要的,要达到咱们的目的,就要让组件在渲染时,可以找到它,所以,咱们能够在主题中给该组件添加这个样式,并把.x-tree-checkbox中的图片文件改为咱们须要的

.x-tree-checkbox {
    margin-right: 4px;
    top: 5px;
    width: 15px;
    height: 15px;
    background-image: url(images/form/checkbox1.png);
}

.x-tree-checkbox-indeterminate {
    background-position: 0 -30px;
}

 

半选实现

代码段:

Ext.create('Ext.window.Window', {
	title: 'Test',
    height: 230,
    width: 400,
    layout: 'fit',
	autoShow:true,
    items: {
        xtype: 'checktree',
        store: Ext.create('Ext.data.TreeStore', {
		    root: {
		        expanded: true,
		        children: [
		            { text: 'child1', leaf: true, checked: false, indeterminate: false},
		            { text: 'child2', expanded: true, checked: false, indeterminate: false, children: [
		                { text: 'child2-1', expanded: true, checked: false, indeterminate: false, children:[
		                 	{ text: 'child2-1-1', leaf: true, checked: false, indeterminate: false},
		                 	{ text: 'child2-1-2', leaf: true, checked: false, indeterminate: false}
		            	] },
		            	{ text: 'child2-2', leaf: true, checked: false, indeterminate: false}
		            ] },
		            { text: 'child3', leaf: true, checked: false, indeterminate: false}
		        ]
		    }
		}),
    	rootVisible: false
 	}
});

点击后的效果:

相关文章
相关标签/搜索