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
那么,该怎么解决呢?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 } });
点击后的效果: