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 } });
點擊後的效果: