Ext [DDTabPanel、FoodImageField、ImageChooser]扩展组件
最后更新于:2022-04-01 12:01:29
**Ext 扩展组件**
开发环境:
System:Windows
WebBrowser:IE6+、Firefox3+
JavaEE Server:tomcat5.0.2.8、tomcat6
IDE:eclipse、MyEclipse 6.5
开发依赖库:
JavaEE5、ext 2.2.2
Email:hoojo_@126.com
Blog:[http://blog.csdn.net/IBM_hoojo](http://blog.csdn.net/IBM_hoojo)
[http://hoojo.cnblogs.com/](http://hoojo.cnblogs.com/)
### 一、Ext.ux.panel.DDTabPanel组件
可以拖动tabPanel的组件
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122b076ec.gif)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122b37ab4.gif)
需要用到的文件
DDTabPanel组件文件:Ext.ux.panel.DDTabPanel.js
DDTabPanel运行示例文件:Ext.hoo.form.DDTabPanel.js
代码如下
ddTabPanelExample.htm
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Basic Component -- DDTabPanel</title>
<meta http-equiv="pragma" content="no-cache"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="expires" content="0"/>
<meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="author" content="hoojo"/>
<meta http-equiv="email" content="hoojo_@126.com"/>
<meta http-equiv="ext-lib" content="version 3.2"/>
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>
<link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"/>
<link rel="stylesheet" type="text/css" href="../css/DDTabPanel.css"/>
<script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext2/ext-all.js"></script>
<script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="Ext.ux.panel.DDTabPanel.js"></script>
<script type="text/javascript" src="Ext.hoo.form.DDTabPanel.js"></script>
</head>
<body>
</body>
</html>
~~~
DDTabPanel.css
~~~
.dd-arrow-down.dd-arrow-down-invisible {
display: none;
visibility: hidden;
}
.dd-arrow-down {
background-image: url(../images/dd-arrow-down.gif);
display: block;
visibility: visible;
z-index: 20000;
position: absolute;
width: 16px;
height: 16px;
top: 0;
left: 0;
background-repeat: no-repeat;
}
html, body {
font: 10pt "Segoe UI","Tahoma","Helvetica","Arial",sans-serif;
padding: 5px;
}
#container {
margin: 5px 10px;
}
~~~
dd-arrow-down.gif
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122b65049.gif)
Ext.hoo.form.DDTabPanel.js
~~~
/**
* @function 可以拖拽的tabPanel
* @auhor: hoojo
* @createDate: Sep 16, 2010 9:25:12 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
* @class Ext.hoo.form.DDTabPanel
* @extends Ext.ux.panel.DDTabPanel
*/
Ext.ns("Ext.hoo.form");
Ext.hoo.form.DDTabPanel = Ext.extend(Ext.ux.panel.DDTabPanel, {
constructor: function () {
Ext.hoo.form.DDTabPanel.superclass.constructor.call(this, {
renderTo: Ext.getBody(),
height: 500,
items: [{
title: "我的主页",
html: "这是一个主页"
}, {
title: "站内新闻",
html: "重大新闻"
}, {
title: "关于我们",
html: "网址建设"
}]
});
}
});
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
Ext.QuickTips.init();
Ext.form.Field.prototype.msgTarget = "qtip";
new Ext.hoo.form.DDTabPanel();
});
~~~
Ext.ux.panel.DDTabPanel.js
~~~
/*global Ext*/
Ext.namespace('Ext.ux.panel');
/**
* <p>A tab panel which supports drag and drop behaviour for tabs. Usage and configuration are identical to {@link Ext.TabPanel}, with the sole exception of two extra configuration options to adjust the drop arrow indicator position.</p>
* <p>This extension can also be created using the <b>ddtabpanel</b> xtype.<br/> </p>
* <p>Based on the code of <a href="http://extjs.com/forum/member.php?u=22731">thommy</a> and <a href="http://extjs.com/forum/member.php?u=37284">rizjoj</a> in the topic <a href="http://extjs.com/forum/showthread.php?t=23264">Draggable Panel in a TabPanel</a>.</p>
* <p>Demo link: <a href="http://extjs-ux.org/repo/authors/Matti/trunk/Ext/ux/panel/DDTabPanel/demo.html">http://extjs-ux.org/repo/authors/Matti/trunk/Ext/ux/panel/DDTabPanel/demo.html</a>
* <br />Forum thread: <a href="http://extjs.com/forum/showthread.php?p=264712">http://extjs.com/forum/showthread.php?p=264712</a><br/> </p>
* <b>CSS Styles:</b>
* <pre><code>.dd-arrow-down.dd-arrow-down-invisible {
display: none;
visibility: hidden;
}
.dd-arrow-down {
background-image: url( <your_down_arrow_image> );
display: block;
visibility: visible;
z-index: 20000;
position: absolute;
width: 16px;
height: 16px;
top: 0;
left: 0;
}</code></pre>
* <br /><b>Example Usage:</b>
* <pre><code>var tabs = new Ext.ux.panel.DDTabPanel({
renderTo: Ext.getBody(),
items: [{
title: 'Tab 1',
html: 'A simple tab'
},{
title: 'Tab 2',
html: 'Another one'
}]
});</code></pre>
* @class Ext.ux.panel.DDTabPanel
* @extends Ext.TabPanel
* @author Original by <a href="http://extjs.com/forum/member.php?u=22731">thommy</a> and <a href="http://extjs.com/forum/member.php?u=37284">rizjoj</a><br />Published and polished by: Mattias Buelens (<a href="http://extjs.com/forum/member.php?u=41421">Matti</a>)
* @license Licensed under the terms of the Open Source <a href="http://www.gnu.org/licenses/lgpl.html">LGPL 3.0 license</a>. Commercial use is permitted to the extent that the code/component(s) do NOT become part of another Open Source or Commercially licensed development library or toolkit without explicit permission.
* @version 1.0.2 (Dec 18, 2008)
*/
Ext.ux.panel.DDTabPanel = Ext.extend(Ext.TabPanel, {
/**
* @cfg {Number} arrowOffsetX
* The horizontal offset for the drop arrow indicator, in pixels (defaults to -9).
*/
arrowOffsetX: -9,
/**
* @cfg {Number} arrowOffsetY
* The vertical offset for the drop arrow indicator, in pixels (defaults to -8).
*/
arrowOffsetY: -8,
// Overwritten: assign the drag and drop group id
/** @private */
initComponent: function() {
Ext.ux.panel.DDTabPanel.superclass.initComponent.call(this);
this.ddGroupId = 'dd-tabpanel-group-' + Ext.ux.panel.DDTabPanel.superclass.getId.call(this);
},
// Overwritten: declare the tab panel as a drop target
/** @private */
initEvents: function(){
Ext.ux.panel.DDTabPanel.superclass.initEvents.call(this);
// Create a drop target for this tab panel
var tabsDDGroup = this.ddGroupId;
this.dd = new Ext.ux.panel.DDTabPanel.DropTarget(this, {
ddGroup: tabsDDGroup
});
// Create a drop arrow indicator
this.arrow = Ext.DomHelper.append(
Ext.getBody(),
'<div class="dd-arrow-down dd-arrow-down-invisible"></div>',
true
);
//this.arrow.dom.style.display = "none";//初始化的时候隐藏
this.arrow.setStyle({display: "none"});
},
// Overwritten: init the drag source after (!) rendering the tab
/** @private */
initTab: function(tab, index){
Ext.ux.panel.DDTabPanel.superclass.initTab.call(this, tab, index);
// Set the initial tab position
tab.position = (index + 1) * 2; // 2, 4, 6, 8, ... (2n)
tab.on('render', function(tab){
// Make this tab a drag source
var id = this.id + '__' + tab.id;
var tabsDDGroup = this.ddGroupId;
tab.ds = new Ext.dd.DragSource(id, {
ddGroup: tabsDDGroup,
dropEl: tab,
dropElHeader: Ext.get(id, true)
});
// Activate this tab before starting the drag action
tab.ds.beforeDragEnter = function(target, event, id){
target.tabpanel.activate(this.dropEl);
//target.tabpanel.arrow.dom.style.display = "block";//显示放入的时候,显示图标
//target.tabpanel.arrow.setStyle({display: "block"});
};
// Activate this tab on mouse down
// Fixed bug which prevents a tab from being activated by clicking it
tab.ds.onMouseDown = (function(event){
this.activate(tab);
}).createDelegate(this);
}, this);
// Force the tab to render
tab.show();
}
});
// Ext.ux.panel.DDTabPanel.DropTarget
// Implements the drop behavior of the tab panel
/** @private */
Ext.ux.panel.DDTabPanel.DropTarget = Ext.extend(Ext.dd.DropTarget, {
constructor: function(tabpanel, config){
this.tabpanel = tabpanel;
// The drop target is the header area of the given tab panel
var target = Ext.select('div.x-tab-panel-header', false, tabpanel.getEl().dom).elements[0];
Ext.ux.panel.DDTabPanel.DropTarget.superclass.constructor.call(this, target, config);
},
notifyOver: function(dd, e, data){
var tabs = this.tabpanel.items;
var last = tabs.length;
if (last < 2) {
return 'x-dd-drop-nodrop';
}
var larrow = this.tabpanel.arrow;
// Getting the absolute X,Y coordinates by encapsulating the dom
// element into an Ext.Element and using getX() and getY() methods.
var panelDom = new Ext.Element(this.el.dom);
var tabPanelLeft = panelDom.getX();
var tabPanelTop = panelDom.getY();
var left;
var eventPosX = e.getPageX();
for (var i = 0; i < last; i++) {
var tab = tabs.itemAt(i);
// Is this tab target of the drop operation?
var tabDom = tab.ds.dropElHeader.dom;
// Getting the absolute X,Y coordinates by encapsulating the dom
// element into an Ext.Element and using getX() and getY() methods.
var tabLeft = new Ext.Element(tabDom).getX();
var tabMiddle = tabLeft + tabDom.clientWidth / 2;
if (eventPosX <= tabMiddle) {
left = tabLeft;
break;
}
}
if (typeof(left) == 'undefined') {
var lastTab = tabs.itemAt(last - 1);
var dom = lastTab.ds.dropElHeader.dom;
left = (tabPanelLeft + dom.offsetLeft + dom.clientWidth) + 3;
}
larrow.setTop(tabPanelTop + this.tabpanel.arrowOffsetY);
larrow.setLeft(left + this.tabpanel.arrowOffsetX);
larrow.removeClass('dd-arrow-down-invisible');
larrow.setStyle({display: "block"});
return 'x-dd-drop-ok';
},
notifyDrop: function(dd, e, data){
this.tabpanel.arrow.addClass('dd-arrow-down-invisible');
var tabPanelOffset = this.tabpanel.el.dom.offsetLeft;
var tabs = this.tabpanel.items;
// At this point the items in 'tabs' are sorted by their positions
var tabDom = new Ext.Element(this.tabpanel.el.dom);
// Getting the absolute X,Y coordinates by encapsulating the dom
// element into an Ext.Element and using getX() and getY() methods.
var eventPosX = e.getPageX() - tabDom.getX();
var last = tabs.length;
var newPos = last;
dd.dropEl.position = last * 2 + 1; // default: 'behind the rest'
for (var i = 0; i < last; i++) {
var tab = tabs.itemAt(i);
// Is this tab target of the drop operation?
var dom = tab.ds.dropElHeader.dom;
var tabLeft = tabPanelOffset + dom.offsetLeft;
var tabRight = tabLeft + dom.clientWidth;
var tabMiddle = tabLeft + dom.clientWidth / 2;
if (eventPosX <= tabRight) {
dd.dropEl.position = eventPosX > tabMiddle ? tab.position + 1 : tab.position - 1;
newPos = eventPosX > tabMiddle ? i + 1 : i;
break;
}
}
dd.proxy.hide();
dd.el.dom.parentNode.insertBefore(dd.el.dom, dd.el.dom.parentNode.childNodes[newPos]);
// Sort tabs by their actual position
tabs.sort('ASC', function(a, b){
return a.position - b.position;
});
// Adjust tab position values
tabs.each(function(tab, index){
tab.position = (index + 1) * 2;
});
var larrow = this.tabpanel.arrow;
larrow.setStyle({display: "none"});
//this.tabpanel.arrow.dom.style.display = "none";
return true;
},
notifyOut: function(dd, e, data) {
this.tabpanel.arrow.addClass('dd-arrow-down-invisible');
}
});
Ext.reg('ddtabpanel', Ext.ux.panel.DDTabPanel);
~~~
### 二、Images choose选择控件
可以选择图片、过滤图片,及显示图片详情
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122b811ab.gif)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122bc3d72.gif)
需要用到的文件
Ext.ux.ImageChooser.css
style.css
chooser.js
chooser组件:Ext.ux.form.ImageField.js
Ext.ux.ImageChooser.js
示例:Ext.hoo.form.FoodImageField.js
代码如下
imageSelectedExample.htm
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Basic Component -- imageChooser</title>
<meta http-equiv="pragma" content="no-cache"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="expires" content="0"/>
<meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="author" content="hoojo"/>
<meta http-equiv="email" content="hoojo_@126.com"/>
<meta http-equiv="ext-lib" content="version 3.2"/>
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>
<link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"/>
<link rel="stylesheet" type="text/css" href="../css/Ext.ux.ImageChooser.css"/>
<link rel="stylesheet" type="text/css" href="../css/style.css"/>
<script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext2/ext-all.js"></script>
<script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="Ext.ux.form.ImageField.js"></script>
<script type="text/javascript" src="Ext.ux.ImageChooser.js"></script>
<script type="text/javascript" src="chooser.js"></script>
<script type="text/javascript" src="Ext.hoo.form.FoodImageField.js"></script>
</head>
<body>
<div id="show" style="margin: 50px;"></div>
<div id="showField" style="margin: 50px;"></div>
<div id="buttons" style="margin:20px;"></div>
<div id="images" style="margin:20px;width:600px;"></div>
</body>
</html>
~~~
Ext.ux.ImageChooser.css
~~~
/*
* Ext JS Library 2.0
* Copyright(c) 2006-2007, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
#img-chooser-dlg .details{
padding: 10px;
text-align: center;
}
#img-chooser-dlg .details-info{
border-top: 1px solid #cccccc;
font: 11px Arial, Helvetica, sans-serif;
margin-top: 5px;
padding-top: 5px;
text-align: left;
}
#img-chooser-dlg .details-info b{
color: #555555;
display: block;
margin-bottom: 4px;
}
#img-chooser-dlg .details-info span{
display: block;
margin-bottom: 5px;
margin-left: 5px;
}
#img-chooser-view{
background: white;
font: 11px Arial, Helvetica, sans-serif;
}
#img-chooser-view .thumb{
background: #dddddd;
padding: 3px;
}
#img-chooser-view .thumb img{
height: 30px;
width: 40px;
}
#img-chooser-view .thumb-wrap{
float: left;
margin: 4px;
margin-right: 0;
padding: 5px;
}
#img-chooser-view .thumb-wrap span{
display: block;
overflow: hidden;
text-align: center;
}
#img-chooser-view .x-view-over{
border:1px solid #dddddd;
background: #efefef url(../resources/images/default/grid/row-over.gif) repeat-x left top;
padding: 4px;
}
#img-chooser-view .x-view-selected{
background: #DFEDFF;
border: 1px solid #6593cf;
padding: 4px;
}
#img-chooser-view .x-view-selected .thumb{
background:transparent;
}
#img-chooser-view .x-view-selected span{
color:#1A4D8F;
}
#img-chooser-view .loading-indicator {
font-size:11px;
background-image:url('../resources/images/grid/loading.gif');
background-repeat: no-repeat;
background-position: left;
padding-left:20px;
margin:10px;
}
~~~
style.css
~~~
.x-form-field-wrap .x-form-trigger{
background:transparent url(../ext2/resources/images/default/form/search-trigger.gif) no-repeat 0 0 !important;
}
.x-form-imagefield {
text-align:right;
padding-right:17px;
}
.ext-safari .x-form-field-wrap .x-form-trigger {
right:-17px !important;
}
.x-form-imagefield-image {
width:34px;
height:34px;
background:#fff;
border: 1px solid #B5B8C8;
}
.images-view .x-window-body{
background: #ffffff;
color: #000000;
}
.images-view .thumb{
border:1px solid #dddddd;
padding: 0px;
height: 34px;
width: 34px;
}
.images-view .thumb-wrap{
float: left;
margin: 4px;
margin-right: 0;
padding: 5px;
cursor: pointer;
}
.images-view .x-view-over{
border:1px solid #cccccc;
background: #eeeeee;
padding: 4px;
}
.images-view .x-view-selected{
background: #ccddee;
border:1px solid #6699cc;
padding: 4px;
}
.images-view .x-view-selected .thumb{
border:1px solid #6699cc;
}
~~~
chooser.js
~~~
/*
* Ext JS Library 2.2.1
* Copyright(c) 2006-2009, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
/*
* Ext JS Library 2.0
* Copyright(c) 2006-2007, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
var ImageChooser = function(config){
this.config = config;
}
ImageChooser.prototype = {
// cache data by image name for easy lookup
lookup : {},
show : function(el, callback){
if(!this.win){
this.initTemplates();
this.store = new Ext.data.JsonStore({
url: this.config.url,
root: 'images',
fields: [
'name', 'url',
{name:'size', type: 'float'},
{name:'lastmod', type:'date', dateFormat:'timestamp'}
],
listeners: {
'load': {fn:function(){ this.view.select(0); }, scope:this, single:true}
}
});
this.store.load();
var formatSize = function(data){
if(data.size < 1024) {
return data.size + " bytes";
} else {
return (Math.round(((data.size*10) / 1024))/10) + " KB";
}
};
var formatData = function(data){
data.shortName = data.name.ellipse(15);
data.sizeString = formatSize(data);
data.dateString = new Date(data.lastmod).format("m/d/Y g:i a");
this.lookup[data.name] = data;
return data;
};
this.view = new Ext.DataView({
tpl: this.thumbTemplate,
singleSelect: true,
overClass:'x-view-over',
itemSelector: 'div.thumb-wrap',
emptyText : '<div style="padding:10px;">No images match the specified filter</div>',
store: this.store,
listeners: {
'selectionchange': {fn:this.showDetails, scope:this, buffer:100},
'dblclick' : {fn:this.doCallback, scope:this},
'loadexception' : {fn:this.onLoadException, scope:this},
'beforeselect' : {fn:function(view){
return view.store.getRange().length > 0;
}}
},
prepareData: formatData.createDelegate(this)
});
var cfg = {
title: 'Choose an Image',
id: 'img-chooser-dlg',
layout: 'border',
minWidth: 500,
minHeight: 300,
modal: true,
closeAction: 'hide',
border: false,
items:[{
id: 'img-chooser-view',
region: 'center',
autoScroll: true,
items: this.view,
tbar:[{
text: 'Filter:'
},{
xtype: 'textfield',
id: 'filter',
selectOnFocus: true,
width: 100,
listeners: {
'render': {fn:function(){
Ext.getCmp('filter').getEl().on('keyup', function(){
this.filter();
}, this, {buffer:500});
}, scope:this}
}
}, ' ', '-', {
text: 'Sort By:'
}, {
id: 'sortSelect',
xtype: 'combo',
typeAhead: true,
triggerAction: 'all',
width: 100,
editable: false,
mode: 'local',
displayField: 'desc',
valueField: 'name',
lazyInit: false,
value: 'name',
store: new Ext.data.SimpleStore({
fields: ['name', 'desc'],
data : [['name', 'Name'],['size', 'File Size'],['lastmod', 'Last Modified']]
}),
listeners: {
'select': {fn:this.sortImages, scope:this}
}
}]
},{
id: 'img-detail-panel',
region: 'east',
split: true,
width: 150,
minWidth: 150,
maxWidth: 250
}],
buttons: [{
id: 'ok-btn',
text: 'OK',
handler: this.doCallback,
scope: this
},{
text: 'Cancel',
handler: function(){ this.win.hide(); },
scope: this
}],
keys: {
key: 27, // Esc key
handler: function(){ this.win.hide(); },
scope: this
}
};
Ext.apply(cfg, this.config);
this.win = new Ext.Window(cfg);
}
this.reset();
this.win.show(el);
this.callback = callback;
this.animateTarget = el;
},
initTemplates : function(){
this.thumbTemplate = new Ext.XTemplate(
'<tpl for=".">',
'<div class="thumb-wrap" id="{name}">',
'<div class="thumb"><img src="{url}" title="{name}"></div>',
'<span>{shortName}</span></div>',
'</tpl>'
);
this.thumbTemplate.compile();
this.detailsTemplate = new Ext.XTemplate(
'<div class="details">',
'<tpl for=".">',
'<img src="{url}"><div class="details-info">',
'<b>Image Name:</b>',
'<span>{name}</span>',
'<b>Size:</b>',
'<span>{sizeString}</span>',
'<b>Last Modified:</b>',
'<span>{dateString}</span></div>',
'</tpl>',
'</div>'
);
this.detailsTemplate.compile();
},
showDetails : function(){
var selNode = this.view.getSelectedNodes();
var detailEl = Ext.getCmp('img-detail-panel').body;
if(selNode && selNode.length > 0){
selNode = selNode[0];
Ext.getCmp('ok-btn').enable();
var data = this.lookup[selNode.id];
detailEl.hide();
this.detailsTemplate.overwrite(detailEl, data);
detailEl.slideIn('l', {stopFx:true,duration:.2});
}else{
Ext.getCmp('ok-btn').disable();
detailEl.update('');
}
},
filter : function(){
var filter = Ext.getCmp('filter');
this.view.store.filter('name', filter.getValue());
this.view.select(0);
},
sortImages : function(){
var v = Ext.getCmp('sortSelect').getValue();
this.view.store.sort(v, v == 'name' ? 'asc' : 'desc');
this.view.select(0);
},
reset : function(){
if(this.win.rendered){
Ext.getCmp('filter').reset();
this.view.getEl().dom.scrollTop = 0;
}
this.view.store.clearFilter();
this.view.select(0);
},
doCallback : function(){
var selNode = this.view.getSelectedNodes()[0];
var callback = this.callback;
var lookup = this.lookup;
this.win.hide(this.animateTarget, function(){
if(selNode && callback){
var data = lookup[selNode.id];
callback(data);
}
});
},
onLoadException : function(v,o){
this.view.getEl().update('<div style="padding:10px;">Error loading images.</div>');
}
};
String.prototype.ellipse = function(maxLength){
if(this.length > maxLength){
return this.substr(0, maxLength-3) + '...';
}
return this;
};
~~~
Ext.ux.form.ImageField.js
~~~
Ext.namespace('Ext.ux.form');
/**
* @class Ext.form.ImageField
* @extends Ext.BoxComponent
* Class for form image fields that provides event handling value handling and other functionality.
* @constructor
* Creates a new ImageField
* @param {Object} config Configuration options
*/
Ext.ux.form.ImageField = Ext.extend(Ext.BoxComponent, {
/**
* @cfg {String} fieldLabel The label text to display next to this field (defaults to '')
*/
/**
* @cfg {String} labelStyle A CSS style specification to apply directly to this field's label (defaults to the
* container's labelStyle value if set, or ''). For example, <code>labelStyle: 'font-weight:bold;'</code>.
*/
/**
* @cfg {String} labelSeparator The standard separator to display after the text of each form label (defaults
* to the value of {@link Ext.layout.FormLayout#labelSeparator}, which is a colon ':' by default). To display
* no separator for this field's label specify empty string ''.
*/
/**
* @cfg {Boolean} hideLabel True to completely hide the label element (defaults to false)
*/
/**
* @cfg {String} clearCls The CSS class used to provide field clearing (defaults to 'x-form-clear-left')
*/
/**
* @cfg {String} itemCls An additional CSS class to apply to the wrapper's form item element of this field (defaults
* to the container's itemCls value if set, or ''). Since it is applied to the item wrapper, it allows you to write
* standard CSS rules that can apply to the field, the label (if specified) or any other element within the markup for
* the field. NOTE: this will not have any effect on fields that are not part of a form.
*/
/**
* @cfg {String} inputType The type attribute for this field -- this is required for all form fields
* to render properly in a FormLayout as it does check this value to determine whether of not to render it.
* 'image' is the default and only value for this property.
*/
inputType : 'image',
/**
* @cfg {Mixed} value A value to initialize this field with (defaults to '').
*/
value : '',
/**
* @cfg {String} name The field's HTML name attribute (defaults to "").
*/
name : '',
/**
* @cfg {String} cls A custom CSS class to apply to the field's underlying element (defaults to "").
*/
/**
* @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-imagefield-invalid")
*/
invalidClass : "x-form-imagefield-invalid",
/**
* @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided
* (defaults to "The value in this field is invalid")
*/
invalidText : "This field is required",
/**
* @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
automatic validation (defaults to false).
*/
validationEvent : 'change',
/**
* @cfg {Number} validationDelay The length of time in milliseconds after a validation event occurs until validation
* is initiated (defaults to 250)
*/
validationDelay : 250,
/**
* @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
* {tag: "input", type: "text", size: "20", autocomplete: "off"})
*/
defaultAutoCreate : {tag: "div"},
/**
* @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-image")
*/
fieldClass : "x-form-imagefield",
/**
* @cfg {String} msgTarget The location where error text should display. Should be one of the following values
* (defaults to 'qtip'):
*/
msgTarget : 'qtip',
/**
* @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field
* (defaults to 'normal').
*/
msgFx : 'normal',
/**
* @cfg {Boolean} disabled True to disable the field (defaults to false).
*/
disabled : false,
/**
* @cfg {Boolean} optional True allow the image field to not have a value (value == '')
* Set this to true when the image field is not required to be specified
* (defaults to false)
*/
optional : false,
/**
* @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
*/
hideTrigger : false,
/**
* @cfg {String} triggerClass A CSS class to apply to the trigger
*/
triggerClass : '',
/**
* @cfg {String} defaultImage The default image to display in the field (default to Ext.BLANK_IMAGE_URL)
*/
defaultImage: Ext.BLANK_IMAGE_URL,
/**
* @cfg {Number} browserWidth The width of the image browser window
*/
browserWidth: 300,
/**
* @cfg {Number} browserHeight The height of the image browser window
*/
browserHeight: 300,
/**
* @cfg {String} browserTitle The title of the image browser window
*/
browserTitle: '请选择图片',
/**
* @cfg {Boolean} alwaysLoadStore True reload the data store every time the image browser opens
*/
alwaysLoadStore: false,
/**
* @cfg {Object} windowConfig Additional configuration for the image browser window
*/
windowConfig: {},
/**
* @cfg {Object} view The {Ext.DataView} of the image browser
*/
view: {},
/**
* @cfg {String} valueField The data store field to return as the field's value
*/
valueField : 'url',
// Private
isStoreLoaded: false,
// private
isFormField : true,
// Private
selections: [],
// Private
selectedRecords: [],
// private
initComponent : function(){
Ext.ux.form.ImageField.superclass.initComponent.call(this);
this.addEvents(
/**
* @event change
* Fires if the field value has changed.
* @param {Ext.ux.form.ImageField} this
* @param {String} newValue The new value
* @param {String} oldValue The original value
*/
'change',
/**
* @event invalid
* Fires after the field has been marked as invalid.
* @param {Ext.ux.form.ImageField} this
* @param {String} msg The validation message
*/
'invalid',
/**
* @event valid
* Fires after the field has been validated with no errors.
* @param {Ext.ux.form.ImageField} this
*/
'valid',
/**
* @event expand
* Fires when the image browser is expanded
* @param {Ext.ux.form.ImageField} this
* @param {Ext.DataView} view The Ext.DataView of the image browser
*/
'expand',
/**
* @event collapse
* Fires when the image browser is collapsed
* @param {Ext.ux.form.ImageField} this
* @param {Ext.DataView} view The Ext.DataView of the image browser
*/
'collapse'
);
// if store was auto loaded, mark it as loaded
if (this.view.store.autoLoad) {
this.isStoreLoaded = true;
}
},
/**
* Returns the name attribute of the field if available
* @return {String} name The field name
*/
getName: function(){
return this.rendered && this.hiddenField.dom.name ? this.hiddenField.dom.name : '';
},
getSelectedRecords : function(){
this.selections = this.view.getSelectedIndexes();
this.selectedRecords = this.view.getSelectedRecords();
return this.selectedRecords;
},
// private
onRender : function(ct, position){
Ext.ux.form.ImageField.superclass.onRender.call(this, ct, position);
if(!this.el){
var cfg = this.getAutoCreate();
this.el = ct.createChild(cfg, position);
}
this.imageEl = this.el.insertFirst({tag: 'img', src: this.defaultImage });
// create hidden field to hold the value for the image field
this.hiddenField = this.imageEl.insertSibling({tag:'input', type:'hidden', name: this.name, id: this.id + '-hidden'}, 'before');
this.el.addClass([this.fieldClass, this.cls]);
this.imageEl.addClass(this.fieldClass + '-image');
this.initValue();
// wrap it up
this.wrap = this.imageEl.wrap({cls: "x-form-field-wrap"});
this.trigger = this.wrap.createChild({tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger"});
if(this.hideTrigger){
this.trigger.setDisplayed(false);
}
this.initTrigger();
},
// private
initTrigger : function(){
this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
this.trigger.addClassOnOver('x-form-trigger-over');
this.trigger.addClassOnClick('x-form-trigger-click');
},
// private
onDestroy : function(){
if(this.trigger){
this.trigger.removeAllListeners();
this.trigger.remove();
}
this.wrap.remove();
Ext.ux.form.ImageField.superclass.onDestroy.call(this);
},
// private
onDisable : function(){
this.wrap.addClass('x-item-disabled');
this.hiddenField.dom.disabled = true;
},
// private
onEnable : function(){
this.wrap.removeClass('x-item-disabled');
this.hiddenField.dom.disabled = false;
},
// private
onShow : function(){
this.wrap.dom.style.display = '';
this.wrap.dom.style.visibility = 'visible';
},
// private
onHide : function(){
this.wrap.dom.style.display = 'none';
},
// private
onSelect: function(){
var selectedRecords = '';
var returnValue = (this.getSelectedRecords().length > 0) ? this.selectedRecords[0].get(this.valueField) : '';
if (returnValue !== this.value) {
this.setValue(returnValue);
}
this.window.hide();
this.fireEvent('collapse', this, this.view);
},
/**
* The function that should handle the trigger's click event. This method does nothing by default until overridden
* by an implementing function.
* @method
* @param {EventObject} e
*/
onTriggerClick : function(e){
if(this.disabled){
return;
}
// load the data store
if (!this.isStoreLoaded) {
this.view.store.load();
this.isStoreLoaded = true;
} else if (this.alwaysLoadStore === true) {
this.view.store.reload();
}
// setup window with forced config
this.windowConfig = Ext.apply(this.windowConfig, {
title: this.browserTitle,
width: this.browserWidth,
height: this.browserHeight,
draggable: false,
resizable: false,
closable: false,
autoScroll: true,
layout: 'fit',
bbar: [{
text: '选择',
handler: this.onSelect,
scope: this
},'->',{
text: '取消',
handler: function(){
this.view.clearSelections();
this.window.hide();
this.fireEvent('collapse', this, this.view);
}, scope: this
}],
items: this.view
},{
shadow: false,
frame: true
});
// create the image browser window
if(!this.window){
this.window = new Ext.Window(this.windowConfig);
this.window.setPagePosition(this.trigger.getRight(), this.trigger.getTop());
this.view.on('dblclick', this.onSelect, this);
}
// show the image browser window
this.window.show();
this.fireEvent('expand', this, this.view);
},
// private
initValue : function(){
if(this.value !== undefined){
this.hiddenField.dom.value = (this.value === null || this.value === undefined ? '' : this.value);
} else {
this.hiddenField.dom.value = '';
}
},
/**
* Returns true if this field has been changed since it was originally loaded and is not disabled.
*/
isDirty : function() {
if(this.disabled) {
return false;
}
return String(this.getValue()) !== String(this.originalValue);
},
// private
afterRender : function(){
Ext.ux.form.ImageField.superclass.afterRender.call(this);
this.initEvents();
},
/**
* Resets the current field value to the originally loaded value and clears any validation messages
*/
reset : function(){
this.setValue(this.originalValue);
this.clearInvalid();
},
// private
initEvents : function(){
if(this.validationEvent !== false){
this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
}
// reference to original value for reset
this.originalValue = this.getValue();
},
/**
* Returns whether or not the field value is currently valid
* @param {Boolean} preventMark True to disable marking the field invalid
* @return {Boolean} True if the value is valid, else false
*/
isValid : function(preventMark){
if(this.disabled){
return true;
}
var restore = this.preventMark;
this.preventMark = preventMark === true;
var v = this.validateValue(this.processValue(this.getRawValue()));
this.preventMark = restore;
return v;
},
/**
* Validates the field value
* @return {Boolean} True if the value is valid, else false
*/
validate : function(){
if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
this.clearInvalid();
return true;
}
return false;
},
// protected - should be overridden by subclasses if necessary to prepare raw values for validation
processValue : function(value){
return value;
},
// private
validateValue : function(value){
if (this.hiddenField.dom.value === '') {
this.markInvalid();
return false;
} else {
return true;
}
},
/**
* Mark this field as invalid, using {@link #msgTarget} to determine how to display the error and
* applying {@link #invalidClass} to the field's element.
* @param {String} msg (optional) The validation message (defaults to {@link #invalidText})
*/
markInvalid : function(msg){
if(!this.rendered || this.preventMark){ // not rendered
return;
}
this.el.addClass(this.invalidClass);
msg = msg || this.invalidText;
switch(this.msgTarget){
case 'qtip':
this.el.dom.qtip = msg;
this.el.dom.qclass = 'x-form-invalid-tip';
if(Ext.QuickTips){ // fix for floating editors interacting with DND
Ext.QuickTips.enable();
}
break;
case 'title':
this.el.dom.title = msg;
break;
case 'under':
if(!this.errorEl){
var elp = this.getErrorCt();
this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
this.errorEl.setWidth(elp.getWidth(true)-20);
}
this.errorEl.update(msg);
Ext.ux.form.ImageField.msgFx[this.msgFx].show(this.errorEl, this);
break;
case 'side':
if(!this.errorIcon){
var elp = this.getErrorCt();
this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
}
this.alignErrorIcon();
this.errorIcon.dom.qtip = msg;
this.errorIcon.dom.qclass = 'x-form-invalid-tip';
this.errorIcon.show();
this.on('resize', this.alignErrorIcon, this);
break;
default:
var t = Ext.getDom(this.msgTarget);
t.innerHTML = msg;
t.style.display = this.msgDisplay;
break;
}
this.fireEvent('invalid', this, msg);
},
// private
getErrorCt : function(){
return this.el.findParent('.x-form-element', 5, true) || // use form element wrap if available
this.el.findParent('.x-form-field-wrap', 5, true); // else direct field wrap
},
// private
alignErrorIcon : function(){
this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
},
/**
* Clear any invalid styles/messages for this field
*/
clearInvalid : function(){
if(!this.rendered || this.preventMark){ // not rendered
return;
}
this.el.removeClass(this.invalidClass);
switch(this.msgTarget){
case 'qtip':
this.el.dom.qtip = '';
break;
case 'title':
this.el.dom.title = '';
break;
case 'under':
if(this.errorEl){
Ext.ux.form.ImageField.msgFx[this.msgFx].hide(this.errorEl, this);
}
break;
case 'side':
if(this.errorIcon){
this.errorIcon.dom.qtip = '';
this.errorIcon.hide();
this.un('resize', this.alignErrorIcon, this);
}
break;
default:
var t = Ext.getDom(this.msgTarget);
t.innerHTML = '';
t.style.display = 'none';
break;
}
this.fireEvent('valid', this);
},
/**
* Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
* @return {Mixed} value The field value
*/
getRawValue : function(){
var v = this.rendered ? this.hiddenField.getValue() : Ext.value(this.value, '');
return v;
},
/**
* Returns the normalized data value (undefined will be returned as ''). To return the raw value see {@link #getRawValue}.
* @return {Mixed} value The field value
*/
getValue : function(){
if(!this.rendered) {
return this.value;
}
var v = this.hiddenField.getValue();
if(v === undefined){
v = '';
}
return v;
},
/**
* Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
* @param {Mixed} value The value to set
*/
setRawValue : function(v){
return this.hiddenField.dom.value = (v === null || v === undefined ? '' : v);
},
/**
* Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
* @param {Mixed} value The value to set
*/
setValue : function(v){
var original = this.value;
this.value = v;
if(this.rendered){
this.hiddenField.dom.value = (v === null || v === undefined ? '' : v);
this.imageEl.dom.src = (v === null || v === undefined ? '' : v);
this.fireEvent('change', this, original, v);
this.validate();
}
}
});
// anything other than normal should be considered experimental
Ext.ux.form.ImageField.msgFx = {
normal : {
show: function(msgEl, f){
msgEl.setDisplayed('block');
},
hide : function(msgEl, f){
msgEl.setDisplayed(false).update('');
}
},
slide : {
show: function(msgEl, f){
msgEl.slideIn('t', {stopFx:true});
},
hide : function(msgEl, f){
msgEl.slideOut('t', {stopFx:true,useDisplay:true});
}
},
slideRight : {
show: function(msgEl, f){
msgEl.fixDisplay();
msgEl.alignTo(f.el, 'tl-tr');
msgEl.slideIn('l', {stopFx:true});
},
hide : function(msgEl, f){
msgEl.slideOut('l', {stopFx:true,useDisplay:true});
}
}
};
Ext.reg('imagefield', Ext.ux.form.ImageField);
~~~
Ext.ux.ImageChooser.js
~~~
Ext.ux.ImageChooser = function(config) {
this.config = config;
this.initTemplates();
this.store = new Ext.data.JsonStore({
url: this.config.url,
root: 'images',
fields: [
'name', 'url'
],
listeners: {
//'load': {fn:function(){ this.view.select(0); }, scope:this, single:true}
}
});
this.store.load();
this.view = new Ext.DataView({
tpl: this.thumbTemplate,
singleSelect: true,
overClass:'x-view-over',
itemSelector: 'div.thumb-wrap',
emptyText : '<div style="padding:10px;">没有图片,请上传</div>',
store: this.store,
listeners: {
'selectionchange': {fn:this.setHideValue, scope:this, buffer:100},
'dblclick' : {fn:this.canelSelect, scope:this, buffer:100}
}
});
var cfg = {
id: 'img-chooser-dlg',
layout: 'border',
border: false,
items:[{
id: 'img-chooser-view',
region: 'center',
autoScroll: true,
items: this.view
}//,{xtype:'textfield',id: this.hideId}
]
};
Ext.apply(cfg, this.config);
this.hideId = this.config.hideId;
Ext.ux.ImageChooser.superclass.constructor.call(this, cfg);
if(this.hideId) this.add({xtype:'hidden',id: this.hideId});
};
Ext.extend(Ext.ux.ImageChooser, Ext.Panel, {
initTemplates : function(){
this.thumbTemplate = new Ext.XTemplate(
'<tpl for=".">',
'<div class="thumb-wrap" id="{name}">',
'<div class="thumb"><img src="{url}" title="{name}"></div>',
'</div>',//<span>{shortName}</span>
'</tpl>'
);
this.thumbTemplate.compile();
},
setHideValue : function(){
var selNodes = this.view.getSelectedNodes();
var hideObj = Ext.getCmp(this.hideId);
if(selNodes&&selNodes.length>0)
hideObj.setValue(selNodes[0].id);
},
setValue : function(value){
if(value)
this.view.select(value);
},
canelSelect : function(view,index,node,e){
view.deselect(index);
var hideObj = Ext.getCmp(this.hideId);
hideObj.setValue('');
}
});
~~~
Ext.hoo.form.FoodImageField.js
~~~
/**
* @function 可以选择图片的field
* @auhor: hoojo
* @createDate: Sep 17, 2010 10:59:58 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
* @class Ext.hoo.form.FoodImageField
* @extends Ext.ux.ImageChooser
*/
Ext.ns("Ext.hoo.form");
Ext.hoo.form.FoodImageChooser = Ext.extend(Ext.ux.ImageChooser, {
constructor: function () {
Ext.hoo.form.FoodImageChooser.superclass.constructor.call(this, {
renderTo: "show",
hideId: 'iconImagesURL',
//fieldLabel: '图标',
url: 'images.json',
height: 120,
width: 225
});
}
});
Ext.hoo.form.FoodImageField = Ext.extend(Ext.ux.form.ImageField, {
constructor: function () {
this.store = new Ext.data.JsonStore({
autoLoad: true,
url: "images.json",
root: 'images',
fields: [
'name', 'url'
],
listeners: {
//'load': {fn:function(){ this.view.select(0); }, scope:this, single:true}
}
});
this.tpl = new Ext.XTemplate(
'<tpl for=".">',
'<div class="thumb-wrap" id="{name}">',
'<div class="thumb"><img src="{url}" title="{name}"></div>',
'</div>',//<span>{shortName}</span>
'</tpl>'
);
this.view = new Ext.DataView({
singleSelect: true,
emptyText : '<div style="padding:10px;">没有图片,请上传</div>',
store: this.store,
tpl: this.tpl
});
Ext.hoo.form.FoodImageField.superclass.constructor.call(this, {
renderTo: "showField",
//fieldLabel: '图标',
defaultImage: '../images/2.png',
height: 120,
width: 225
});
}
});
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
Ext.QuickTips.init();
Ext.form.Field.prototype.msgTarget = "qtip";
//new Ext.hoo.form.FoodImageChooser();
//new Ext.hoo.form.FoodImageField();
var chooser, btn;
function insertImage(data){
Ext.DomHelper.append('images', {
tag: 'img', src: data.url, style:'margin:10px;visibility:hidden;'
}, true).show(true).frame();
btn.focus();
};
function choose(btn){
if(!chooser){
chooser = new ImageChooser({
url:'images2.json',
width:515,
height:350
});
}
chooser.show(btn.getEl(), insertImage);
};
btn = new Ext.Button({
text: "Insert Image",
handler: choose,
renderTo: 'buttons'
});
});
~~~
Images.json 测试数据
~~~
{images:[{
name:'水果1号',url:'../images/2.png'
},{
name:'水果2号',url:'../images/2.png'
},{
name:'水果3号',url:'../images/2.png'
},{
name:'水果4号',url:'../images/2.png'
},{
name:'水果5号',url:'../images/2.png'
},{
name:'水果6号',url:'../images/2.png'
}]}
~~~
Images2.json
~~~
{images:[{
name:'水果1号',url:'../images/2.png',size: 22.2, lastmod: 2009-06-05
},{
name:'水果2号',url:'../images/2.png',size: 52.2, lastmod: 2009-08-07
},{
name:'水果3号',url:'../images/2.png',size: 44.2, lastmod: 2009-03-06
},{
name:'水果4号',url:'../images/2.png',size: 25.7, lastmod: 2009-06-04
},{
name:'水果5号',url:'../images/2.png',size: 55.3, lastmod: 2010-06-22
},{
name:'水果6号',url:'../images/2.png',size: 77.8, lastmod: "2009-09-15"
}]}
~~~
ExtJS Form扩展组件[ColorFiled, DateTimeFiled, IconCombo, MultiComboBox, DynamicTreeCombox]
最后更新于:2022-04-01 12:01:26
支持Form颜色选择组件、日期时间选择组件、带图标的下拉列表、多选下来列表、动态下拉列表树等组件
开发环境:
System:Windows
WebBrowser:IE6+、Firefox3+
JavaEE Server:tomcat5.0.2.8、tomcat6
IDE:eclipse、MyEclipse 8
开发依赖库:
JavaEE5、ext 2.2.2
Email:hoojo_@126.com
Blog:[http://blog.csdn.net/IBM_hoojo](http://blog.csdn.net/IBM_hoojo)
[http://hoojo.cnblogs.com/](http://hoojo.cnblogs.com/)
### 一、ColoFieldr组件
可以选择一些常用的颜色
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe1229e2976.gif)
需要用到的文件
ColorField组件文件:Ext.form.ColorField.js
ColorField运行示例文件:Ext.hoo.for.ColorField.js
代码如下
Color.html
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>form Component -- DateTimeField</title>
<meta http-equiv="pragma" content="no-cache"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="expires" content="0"/>
<meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="author" content="hoojo"/>
<meta http-equiv="email" content="hoojo_@126.com"/>
<meta http-equiv="ext-lib" content="version 2.2"/>
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>
<link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"/>
<script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext2/ext-all.js"></script>
<script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="Ext.form.ColorField.js"></script>
<script type="text/javascript" src="Ext.hoo.for.ColorField.js"></script>
</head>
<body>
<div id="show" style="float: left; margin: 100px 0 0 100px;"></div>
</body>
</html>
~~~
Ext.form.ColorField.js
~~~
/**
* @class Ext.form.ColorField
* @extends Ext.form.TriggerField
* Provides a very simple color form field with a ColorMenu dropdown.
* Values are stored as a six-character hex value without the '#'.
* I.e. 'ffffff'
* @constructor
* Create a new ColorField
* <br />Example:
* <pre><code>
var cf = new Ext.form.ColorField({
fieldLabel: 'Color',
hiddenName:'pref_sales',
showHexValue:true
});
</code></pre>
* @param {Object} config
*/
Ext.form.ColorField = function(config){
Ext.form.ColorField.superclass.constructor.call(this, config);
//this.on('render', this.handleRender);
};
Ext.extend(Ext.form.ColorField, Ext.form.TriggerField, {
/**
* @cfg {Boolean} showHexValue
* True to display the HTML Hexidecimal Color Value in the field
* so it is manually editable.
*/
showHexValue : false,
/**
* @cfg {String} triggerClass
* An additional CSS class used to style the trigger button. The trigger will always get the
* class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-color-trigger'
* which displays a calendar icon).
*/
triggerClass : 'x-form-color-trigger',
/**
* @cfg {String/Object} autoCreate
* A DomHelper element spec, or true for a default element spec (defaults to
* {tag: "input", type: "text", size: "10", autocomplete: "off"})
*/
// private
defaultAutoCreate : {tag: "input", type: "text", size: "10",
autocomplete: "off", maxlength:"6"},
/**
* @cfg {String} lengthText
* A string to be displayed when the length of the input field is
* not 3 or 6, i.e. 'fff' or 'ffccff'.
*/
lengthText: "Color hex values must be either 3 or 6 characters.",
//text to use if blank and allowBlank is false
blankText: "Must have a hexidecimal value in the format ABCDEF.",
/**
* @cfg {String} color
* A string hex value to be used as the default color. Defaults
* to 'FFFFFF' (white).
*/
defaultColor: 'FFFFFF',
maskRe: /[a-f0-9]/i,
// These regexes limit input and validation to hex values
regex: /[a-f0-9]/i,
//private
curColor: 'ffffff',
initComponent:function(){
Ext.form.ColorField.superclass.initComponent.call(this);
this.addEvents('click','change', 'select');
},
onChange: function (field, newVal, oldVal) {
alert(newVal);
},
onRender : function(ct, position){
Ext.form.ColorField.superclass.onRender.call(this, ct, position);
this.handleRender();
},
// private
validateValue : function(value){
if(!this.showHexValue) {
return true;
}
if(value.length<1) {
this.el.setStyle({
'background-color':'#' + this.defaultColor
});
if(!this.allowBlank) {
this.markInvalid(String.format(this.blankText, value));
return false
}
return true;
}
if(value.length!=3 && value.length!=6 ) {
this.markInvalid(String.format(this.lengthText, value));
return false;
}
this.setColor(value);
return true;
},
// private
validateBlur : function(){
return !this.menu || !this.menu.isVisible();
},
// Manually apply the invalid line image since the background
// was previously cleared so the color would show through.
markInvalid : function( msg ) {
Ext.form.ColorField.superclass.markInvalid.call(this, msg);
this.el.setStyle({
'background-image': 'url(../lib/resources/images/default/grid/invalid_line.gif)'
});
},
/**
* Returns the current color value of the color field
* @return {String} value The hexidecimal color value
*/
getValue : function(){
return this.curValue || this.defaultValue || "FFFFFF";
},
/**
* Sets the value of the color field. Format as hex value 'FFFFFF'
* without the '#'.
* @param {String} hex The color value
*/
setValue : function(hex){
Ext.form.ColorField.superclass.setValue.call(this, hex);
this.setColor(hex);
},
/**
* Sets the current color and changes the background.
* Does *not* change the value of the field.
* @param {String} hex The color value.
*/
setColor : function(hex) {
this.curColor = hex;
this.el.setStyle( {
'background-color': '#' + hex,
'background-image': 'none'
});
if(!this.showHexValue) {
this.el.setStyle({
'text-indent': '-100px'
});
if(Ext.isIE) {
this.el.setStyle({
'margin-left': '100px'
});
}
}
},
handleRender: function() {
this.setDefaultColor();
},
setDefaultColor : function() {
this.setValue(this.defaultColor);
},
// private
menuListeners : {
select: function(m, d){
this.setValue(d);
},
show : function(){ // retain focus styling
this.onFocus();
},
hide : function(){
this.focus();
var ml = this.menuListeners;
this.menu.un("select", ml.select, this);
this.menu.un("show", ml.show, this);
this.menu.un("hide", ml.hide, this);
}
},
//private
handleSelect : function(palette, selColor) {
this.setValue(selColor);
this.fireEvent("click", this, selColor);
this.fireEvent("change", this, selColor);
this.fireEvent("select", this, selColor);
},
// private
// Implements the default empty TriggerField.onTriggerClick function to display the ColorPicker
onTriggerClick : function(){
if(this.disabled){
return;
}
if(this.menu == null){
this.menu = new Ext.menu.ColorMenu();
this.menu.palette.on('select', this.handleSelect, this );
}
this.menu.on(Ext.apply({}, this.menuListeners, {
scope:this
}));
this.menu.show(this.el, "tl-bl?");
}
});
~~~
Ext.hoo.for.ColorField.js
~~~
/**
* @function 颜色选择器
* @auhor: hoojo
* @createDate: Sep 11, 2010 10:35:15 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
* @class Ext.hoo.form.ColorField
* @extends Ext.form.ColorField
*/
Ext.ns("Ext.hoo.form");
Ext.hoo.form.ColorField = Ext.extend(Ext.form.ColorField, {
constructor: function () {
Ext.hoo.form.ColorField.superclass.constructor.call(this, {
//fieldLabel: "plase selected",
renderTo: "show",
width: 160,
defaultColor: "00FF00",
curColor: "00FF00",
showHexValue: true,
listeners: {
"select": function (f, v) {
alert(this.getValue() + "##" + v);
}
}
});
}
});
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
Ext.QuickTips.init();
Ext.form.Field.prototype.msgTarget = "qtip";
new Ext.hoo.form.ColorField();
});
~~~
### 二、日期时间选择控件
可以选择日期、时间
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122a1a9ce.gif)
需要用到的文件
Spinner.js
Spinner.css
SpinnerField.js
日期时间组件:Ext.ux.form.DateTimeField.js
示例:Ext.hoo.form.DateTimeField.js
代码如下
dateTimeFieldExample.htm
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>form Component -- MultiComboBox</title>
<meta http-equiv="pragma" content="no-cache"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="expires" content="0"/>
<meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="author" content="hoojo"/>
<meta http-equiv="email" content="hoojo_@126.com"/>
<meta http-equiv="ext-lib" content="version 3.2"/>
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>
<link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css"/>
<link rel="stylesheet" type="text/css" href="../css/Spinner.css"/>
<script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext/ext-all.js"></script>
<script type="text/javascript" src="../ext/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="Spinner.js"></script>
<script type="text/javascript" src="SpinnerField.js"></script>
<script type="text/javascript" src="Ext.ux.form.DateTimeField.js"></script>
<script type="text/javascript" src="Ext.hoo.form.DateTimeField.js"></script>
</head>
<body>
<div id="show" style="float: left; margin: 100px 0 0 100px;"></div>
</body>
</html>
~~~
Spinner.css
~~~
/*!
* Ext JS Library 3.1.1
* Copyright(c) 2006-2010 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
.x-form-spinner-proxy{
/*background-color:#ff00cc;*/
}
.x-form-field-wrap .x-form-spinner-trigger {
background:transparent url('../images/spinner.gif') no-repeat 0 0;
}
.x-form-field-wrap .x-form-spinner-overup{
background-position:-17px 0;
}
.x-form-field-wrap .x-form-spinner-clickup{
background-position:-34px 0;
}
.x-form-field-wrap .x-form-spinner-overdown{
background-position:-51px 0;
}
.x-form-field-wrap .x-form-spinner-clickdown{
background-position:-68px 0;
}
.x-trigger-wrap-focus .x-form-spinner-trigger{
background-position:-85px 0;
}
.x-trigger-wrap-focus .x-form-spinner-overup{
background-position:-102px 0;
}
.x-trigger-wrap-focus .x-form-spinner-clickup{
background-position:-119px 0;
}
.x-trigger-wrap-focus .x-form-spinner-overdown{
background-position:-136px 0;
}
.x-trigger-wrap-focus .x-form-spinner-clickdown{
background-position:-153px 0;
}
.x-trigger-wrap-focus .x-form-trigger{
border-bottom: 1px solid #7eadd9;
}
.x-form-field-wrap .x-form-spinner-splitter {
line-height:1px;
font-size:1px;
background:transparent url('../images/spinner-split.gif') no-repeat 0 0;
position:absolute;
cursor: n-resize;
}
.x-trigger-wrap-focus .x-form-spinner-splitter{
background-position:-14px 0;
}
.x-date-bottom {
font-size: 12px;
}
.x-date-menu {
height: 200px;
}
~~~
图片
spinner.gif ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122a492ab.gif)
spinner-split.gif ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122a668ab.gif)
Spinner.js
~~~
/*!
* Ext JS Library 3.1.1
* Copyright(c) 2006-2010 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.ux.Spinner
* @extends Ext.util.Observable
* Creates a Spinner control utilized by Ext.ux.form.SpinnerField
*/
Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
incrementValue: 1,
alternateIncrementValue: 5,
triggerClass: 'x-form-spinner-trigger',
splitterClass: 'x-form-spinner-splitter',
alternateKey: Ext.EventObject.shiftKey,
defaultValue: 0,
accelerate: false,
constructor: function(config){
Ext.ux.Spinner.superclass.constructor.call(this, config);
Ext.apply(this, config);
this.mimicing = false;
},
init: function(field){
this.field = field;
field.afterMethod('onRender', this.doRender, this);
field.afterMethod('onEnable', this.doEnable, this);
field.afterMethod('onDisable', this.doDisable, this);
field.afterMethod('afterRender', this.doAfterRender, this);
field.afterMethod('onResize', this.doResize, this);
field.afterMethod('onFocus', this.doFocus, this);
field.beforeMethod('onDestroy', this.doDestroy, this);
},
doRender: function(ct, position){
var el = this.el = this.field.getEl();
var f = this.field;
if (!f.wrap) {
f.wrap = this.wrap = el.wrap({
cls: "x-form-field-wrap"
});
}
else {
this.wrap = f.wrap.addClass('x-form-field-wrap');
}
this.trigger = this.wrap.createChild({
tag: "img",
src: Ext.BLANK_IMAGE_URL,
cls: "x-form-trigger " + this.triggerClass
});
if (!f.width) {
this.wrap.setWidth(el.getWidth() + this.trigger.getWidth());
}
this.splitter = this.wrap.createChild({
tag: 'div',
cls: this.splitterClass,
style: 'width:13px; height:2px;'
});
this.splitter.setRight((Ext.isIE) ? 1 : 2).setTop(10).show();
this.proxy = this.trigger.createProxy('', this.splitter, true);
this.proxy.addClass("x-form-spinner-proxy");
this.proxy.setStyle('left', '0px');
this.proxy.setSize(14, 1);
this.proxy.hide();
this.dd = new Ext.dd.DDProxy(this.splitter.dom.id, "SpinnerDrag", {
dragElId: this.proxy.id
});
this.initTrigger();
this.initSpinner();
},
doAfterRender: function(){
var y;
if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) {
this.el.position();
this.el.setY(y);
}
},
doEnable: function(){
if (this.wrap) {
this.wrap.removeClass(this.field.disabledClass);
}
},
doDisable: function(){
if (this.wrap) {
this.wrap.addClass(this.field.disabledClass);
this.el.removeClass(this.field.disabledClass);
}
},
doResize: function(w, h){
if (typeof w == 'number') {
this.el.setWidth(w - this.trigger.getWidth());
}
this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
},
doFocus: function(){
if (!this.mimicing) {
this.wrap.addClass('x-trigger-wrap-focus');
this.mimicing = true;
Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, {
delay: 10
});
this.el.on('keydown', this.checkTab, this);
}
},
// private
checkTab: function(e){
if (e.getKey() == e.TAB) {
this.triggerBlur();
}
},
// private
mimicBlur: function(e){
if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) {
this.triggerBlur();
}
},
// private
triggerBlur: function(){
this.mimicing = false;
Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
this.el.un("keydown", this.checkTab, this);
this.field.beforeBlur();
this.wrap.removeClass('x-trigger-wrap-focus');
this.field.onBlur.call(this.field);
},
initTrigger: function(){
this.trigger.addClassOnOver('x-form-trigger-over');
this.trigger.addClassOnClick('x-form-trigger-click');
},
initSpinner: function(){
this.field.addEvents({
'spin': true,
'spinup': true,
'spindown': true
});
this.keyNav = new Ext.KeyNav(this.el, {
"up": function(e){
e.preventDefault();
this.onSpinUp();
},
"down": function(e){
e.preventDefault();
this.onSpinDown();
},
"pageUp": function(e){
e.preventDefault();
this.onSpinUpAlternate();
},
"pageDown": function(e){
e.preventDefault();
this.onSpinDownAlternate();
},
scope: this
});
this.repeater = new Ext.util.ClickRepeater(this.trigger, {
accelerate: this.accelerate
});
this.field.mon(this.repeater, "click", this.onTriggerClick, this, {
preventDefault: true
});
this.field.mon(this.trigger, {
mouseover: this.onMouseOver,
mouseout: this.onMouseOut,
mousemove: this.onMouseMove,
mousedown: this.onMouseDown,
mouseup: this.onMouseUp,
scope: this,
preventDefault: true
});
this.field.mon(this.wrap, "mousewheel", this.handleMouseWheel, this);
this.dd.setXConstraint(0, 0, 10)
this.dd.setYConstraint(1500, 1500, 10);
this.dd.endDrag = this.endDrag.createDelegate(this);
this.dd.startDrag = this.startDrag.createDelegate(this);
this.dd.onDrag = this.onDrag.createDelegate(this);
},
onMouseOver: function(){
if (this.disabled) {
return;
}
var middle = this.getMiddle();
this.tmpHoverClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-overup' : 'x-form-spinner-overdown';
this.trigger.addClass(this.tmpHoverClass);
},
//private
onMouseOut: function(){
this.trigger.removeClass(this.tmpHoverClass);
},
//private
onMouseMove: function(){
if (this.disabled) {
return;
}
var middle = this.getMiddle();
if (((Ext.EventObject.getPageY() > middle) && this.tmpHoverClass == "x-form-spinner-overup") ||
((Ext.EventObject.getPageY() < middle) && this.tmpHoverClass == "x-form-spinner-overdown")) {
}
},
//private
onMouseDown: function(){
if (this.disabled) {
return;
}
var middle = this.getMiddle();
this.tmpClickClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-clickup' : 'x-form-spinner-clickdown';
this.trigger.addClass(this.tmpClickClass);
},
//private
onMouseUp: function(){
this.trigger.removeClass(this.tmpClickClass);
},
//private
onTriggerClick: function(){
if (this.disabled || this.el.dom.readOnly) {
return;
}
var middle = this.getMiddle();
var ud = (Ext.EventObject.getPageY() < middle) ? 'Up' : 'Down';
this['onSpin' + ud]();
},
//private
getMiddle: function(){
var t = this.trigger.getTop();
var h = this.trigger.getHeight();
var middle = t + (h / 2);
return middle;
},
//private
//checks if control is allowed to spin
isSpinnable: function(){
if (this.disabled || this.el.dom.readOnly) {
Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly
return false;
}
return true;
},
handleMouseWheel: function(e){
//disable scrolling when not focused
if (this.wrap.hasClass('x-trigger-wrap-focus') == false) {
return;
}
var delta = e.getWheelDelta();
if (delta > 0) {
this.onSpinUp();
e.stopEvent();
}
else
if (delta < 0) {
this.onSpinDown();
e.stopEvent();
}
},
//private
startDrag: function(){
this.proxy.show();
this._previousY = Ext.fly(this.dd.getDragEl()).getTop();
},
//private
endDrag: function(){
this.proxy.hide();
},
//private
onDrag: function(){
if (this.disabled) {
return;
}
var y = Ext.fly(this.dd.getDragEl()).getTop();
var ud = '';
if (this._previousY > y) {
ud = 'Up';
} //up
if (this._previousY < y) {
ud = 'Down';
} //down
if (ud != '') {
this['onSpin' + ud]();
}
this._previousY = y;
},
//private
onSpinUp: function(){
if (this.isSpinnable() == false) {
return;
}
if (Ext.EventObject.shiftKey == true) {
this.onSpinUpAlternate();
return;
}
else {
this.spin(false, false);
}
this.field.fireEvent("spin", this);
this.field.fireEvent("spinup", this);
},
//private
onSpinDown: function(){
if (this.isSpinnable() == false) {
return;
}
if (Ext.EventObject.shiftKey == true) {
this.onSpinDownAlternate();
return;
}
else {
this.spin(true, false);
}
this.field.fireEvent("spin", this);
this.field.fireEvent("spindown", this);
},
//private
onSpinUpAlternate: function(){
if (this.isSpinnable() == false) {
return;
}
this.spin(false, true);
this.field.fireEvent("spin", this);
this.field.fireEvent("spinup", this);
},
//private
onSpinDownAlternate: function(){
if (this.isSpinnable() == false) {
return;
}
this.spin(true, true);
this.field.fireEvent("spin", this);
this.field.fireEvent("spindown", this);
},
spin: function(down, alternate){
var v = parseFloat(this.field.getValue());
var incr = (alternate == true) ? this.alternateIncrementValue : this.incrementValue;
(down == true) ? v -= incr : v += incr;
v = (isNaN(v)) ? this.defaultValue : v;
v = this.fixBoundries(v);
this.field.setRawValue(v);
},
fixBoundries: function(value){
var v = value;
if (this.field.minValue != undefined && v < this.field.minValue) {
v = this.field.minValue;
}
if (this.field.maxValue != undefined && v > this.field.maxValue) {
v = this.field.maxValue;
}
return this.fixPrecision(v);
},
// private
fixPrecision: function(value){
var nan = isNaN(value);
if (!this.field.allowDecimals || this.field.decimalPrecision == -1 || nan || !value) {
return nan ? '' : value;
}
return parseFloat(parseFloat(value).toFixed(this.field.decimalPrecision));
},
doDestroy: function(){
if (this.trigger) {
this.trigger.remove();
}
if (this.wrap) {
this.wrap.remove();
delete this.field.wrap;
}
if (this.splitter) {
this.splitter.remove();
}
if (this.dd) {
this.dd.unreg();
this.dd = null;
}
if (this.proxy) {
this.proxy.remove();
}
if (this.repeater) {
this.repeater.purgeListeners();
}
}
});
//backwards compat
Ext.form.Spinner = Ext.ux.Spinner;
~~~
SpinnerField.js
~~~
/*!
* Ext JS Library 3.1.1
* Copyright(c) 2006-2010 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.ns('Ext.ux.form');
/**
* @class Ext.ux.form.SpinnerField
* @extends Ext.form.NumberField
* Creates a field utilizing Ext.ux.Spinner
* @xtype spinnerfield
*/
Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
actionMode: 'wrap',
deferHeight: true,
autoSize: Ext.emptyFn,
onBlur: Ext.emptyFn,
adjustSize: Ext.BoxComponent.prototype.adjustSize,
constructor: function(config) {
var spinnerConfig = Ext.copyTo({}, config, 'incrementValue,alternateIncrementValue,accelerate,defaultValue,triggerClass,splitterClass');
var spl = this.spinner = new Ext.ux.Spinner(spinnerConfig);
var plugins = config.plugins
? (Ext.isArray(config.plugins)
? config.plugins.push(spl)
: [config.plugins, spl])
: spl;
Ext.ux.form.SpinnerField.superclass.constructor.call(this, Ext.apply(config, {plugins: plugins}));
},
// private
getResizeEl: function(){
return this.wrap;
},
// private
getPositionEl: function(){
return this.wrap;
},
// private
alignErrorIcon: function(){
if (this.wrap) {
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
}
},
validateBlur: function(){
return true;
}
});
Ext.reg('spinnerfield', Ext.ux.form.SpinnerField);
//backwards compat
Ext.form.SpinnerField = Ext.ux.form.SpinnerField;
~~~
Ext.ux.form.DateTimeField.js
~~~
Ext.ns('Ext.ux.form');
Ext.ux.form.TimePickerField = function(config){
Ext.ux.form.TimePickerField.superclass.constructor.call(this, config);
}
Ext.extend(Ext.ux.form.TimePickerField, Ext.form.Field, {
defaultAutoCreate: {
tag: 'div'
},
cls: 'x-form-timepickerfield',
hoursSpinner: null,
minutesSpinner: null,
secondsSpinner: null,
spinnerCfg: {
width: 40
},
spinnerFixBoundries: function(value){
if (value < this.field.minValue) {
value = this.field.maxValue;
}
if (value > this.field.maxValue) {
value = this.field.minValue;
}
return this.fixPrecision(value);
},
onRender: function(ct, position){
Ext.ux.form.TimePickerField.superclass.onRender.call(this, ct, position);
this.rendered = false;
this.date = new Date();
var values = {};
if (this.value) {
values = this._valueSplit(this.value);
this.date.setHours(values.h);
this.date.setMinutes(values.m);
this.date.setSeconds(values.s);
delete this.value;
}
else {
values = {
h: this.date.getHours(),
m: this.date.getMinutes(),
s: this.date.getSeconds()
};
}
var spinnerWrap = Ext.DomHelper.append(this.el, {
tag: 'div'
});
var cfg = Ext.apply({}, this.spinnerCfg, {
renderTo: spinnerWrap,
readOnly: this.readOnly,
disabled: this.disabled,
listeners: {
spin: {
fn: this.onSpinnerChange,
scope: this
},
valid: {
fn: this.onSpinnerChange,
scope: this
},
afterrender: {
fn: function(spinner){
spinner.wrap.applyStyles('float: left');
},
single: true
}
}
});
this.hoursSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {
minValue: 0,
maxValue: 23,
cls: 'first',
value: values.h
}));
this.minutesSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {
minValue: 0,
maxValue: 59,
value: values.m
}));
this.secondsSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {
minValue: 0,
maxValue: 59,
value: values.s
}));
Ext.DomHelper.append(spinnerWrap, {
tag: 'div',
cls: 'x-form-clear-left'
});
this.rendered = true;
},
_valueSplit: function(v){
var split = v.split(':');
return {
h: split.length > 0 ? split[0] : 0,
m: split.length > 1 ? split[1] : 0,
s: split.length > 2 ? split[2] : 0
};
},
onSpinnerChange: function(){
if (!this.rendered) {
return;
}
this.fireEvent('change', this, this.getRawValue());
},
disable: function(){
Ext.ux.form.TimePickerField.superclass.disable.call(this);
this.hoursSpinner.disable();
this.minutesSpinner.disable();
this.secondsSpinner.disable();
},
enable: function(){
Ext.ux.form.TimePickerField.superclass.enable.call(this);
this.hoursSpinner.enable();
this.minutesSpinner.enable();
this.secondsSpinner.enable();
},
setReadOnly: function(r){
Ext.ux.form.TimePickerField.superclass.setReadOnly.call(this, r);
this.hoursSpinner.setReadOnly(r);
this.minutesSpinner.setReadOnly(r);
this.secondsSpinner.setReadOnly(r);
},
clearInvalid: function(){
Ext.ux.form.TimePickerField.superclass.clearInvalid.call(this);
this.hoursSpinner.clearInvalid();
this.minutesSpinner.clearInvalid();
this.secondsSpinner.clearInvalid();
},
getRawValue: function(){
if (!this.hoursSpinner) {
this.date = new Date();
return {
h: this.date.getHours(),
m: this.date.getMinutes(),
s: this.date.getSeconds()
};
}
else {
return {
h: this.hoursSpinner.getValue(),
m: this.minutesSpinner.getValue(),
s: this.secondsSpinner.getValue()
};
}
},
setRawValue: function(v){
this.hoursSpinner.setValue(v.h);
this.minutesSpinner.setValue(v.m);
this.secondsSpinner.setValue(v.s);
},
isValid: function(preventMark){
return this.hoursSpinner.isValid(preventMark) &&
this.minutesSpinner.isValid(preventMark) &&
this.secondsSpinner.isValid(preventMark);
},
validate: function(){
return this.hoursSpinner.validate() &&
this.minutesSpinner.validate() &&
this.secondsSpinner.validate();
},
getValue: function(){
var v = this.getRawValue();
return String.leftPad(v.h, 2, '0') + ':' +
String.leftPad(v.m, 2, '0') +
':' +
String.leftPad(v.s, 2, '0');
},
setValue: function(value){
if (!this.rendered) {
this.value = value;
return;
}
value = this._valueSplit(value);
this.setRawValue(value);
this.validate();
}
});
Ext.form.TimePickerField = Ext.ux.form.TimePickerField;
Ext.reg('timepickerfield', Ext.form.TimePickerField);
Ext.ns('Ext.ux.form');
Ext.DateTimePicker = Ext.extend(Ext.DatePicker, {
timeFormat: 'g:i:s A',
timeLabel: '时间',
timeWidth: 100,
initComponent: function(){
Ext.DateTimePicker.superclass.initComponent.call(this);
this.id = Ext.id();
},
onRender: function(container, position){
Ext.DateTimePicker.superclass.onRender.apply(this, arguments);
var table = Ext.get(Ext.DomQuery.selectNode('table tbody', container.dom));
var tfEl = Ext.DomHelper.insertBefore(table.last(), {
tag: 'tr',
children: [{
tag: 'td',
cls: 'x-date-bottom',
html: this.timeLabel,
style: 'width:30;'
}, {
tag: 'td',
cls: 'x-date-bottom ux-timefield',
style: "height: 20px;",
colspan: '2'
}]
}, true);
this.tf.render(table.child('td.ux-timefield'));
var p = this.getEl().parent('div.x-layer');
if (p) {
p.setStyle("height", p.getHeight() + 31);
}
},
setValue: function(value){
var old = this.value;
if (!this.tf) {
this.tf = new Ext.ux.form.TimePickerField();
this.tf.ownerCt = this;
}
this.value = this.getDateTime(value);
},
getDateTime: function(value){
if (this.tf) {
var dt = new Date();
var timeval = this.tf.getValue();
value = Date.parseDate(value.format(this.dateFormat) + ' ' + this.tf.getValue(), this.format);
}
return value;
},
selectToday: function(){
if (this.todayBtn && !this.todayBtn.disabled) {
this.value = this.getDateTime(new Date());
this.fireEvent("select", this, this.value);
}
}
});
Ext.reg('datetimepickerfield', Ext.DateTimePicker);
if (parseInt(Ext.version.substr(0, 1), 10) > 2) {
Ext.menu.DateTimeItem = Ext.DateTimePicker;
Ext.override(Ext.menu.DateMenu, {
initComponent: function(){
this.on('beforeshow', this.onBeforeShow, this);
if (this.strict = (Ext.isIE7 && Ext.isStrict)) {
this.on('show', this.onShow, this, {
single: true,
delay: 20
});
}
Ext.apply(this, {
plain: true,
showSeparator: false,
items: this.picker = new Ext.DatePicker(Ext.apply({
internalRender: this.strict || !Ext.isIE,
ctCls: 'x-menu-date-item'
}, this.initialConfig))
});
Ext.menu.DateMenu.superclass.initComponent.call(this);
this.relayEvents(this.picker, ["select"]);
this.on('select', this.menuHide, this);
if (this.handler) {
this.on('select', this.handler, this.scope || this);
}
}
});
}
else {
Ext.menu.DateTimeItem = function(config){
Ext.menu.DateTimeItem.superclass.constructor.call(this, new Ext.DateTimePicker(config), config);
this.picker = this.component;
alert(this.picker);
this.addEvents('select');
this.picker.on("render", function(picker){
picker.getEl().swallowEvent("click");
picker.container.addClass("x-menu-date-item");
});
this.picker.on("select", this.onSelect, this);
};
Ext.extend(Ext.menu.DateTimeItem, Ext.menu.DateMenu, {
onSelect: function(picker, date){
this.fireEvent("select", this, date, picker);
Ext.menu.DateTimeItem.superclass.handleClick.call(this);
}
});
}
Ext.menu.DateTimeMenu = function(config){
Ext.menu.DateTimeMenu.superclass.constructor.call(this, config);
this.plain = true;
var di = new Ext.menu.DateTimeItem(config);
this.add(di);
this.picker = di;
this.relayEvents(di, ["select"]);
this.on('beforeshow', function(){
if (this.picker) {
this.picker.hideMonthPicker(true);
}
}, this);
};
Ext.extend(Ext.menu.DateTimeMenu, Ext.menu.Menu, {
cls: 'x-date-menu',
beforeDestroy: function(){
this.picker.destroy();
},
hide: function(deep){
if (this.picker.tf.innerList) {
if ((Ext.EventObject.within(this.picker.tf.innerList)) || (Ext.get(Ext.EventObject.getTarget()) == this.picker.tf.innerList))
return false;
}
if (this.el && this.isVisible()) {
this.fireEvent("beforehide", this);
if (this.activeItem) {
this.activeItem.deactivate();
this.activeItem = null;
}
this.el.hide();
this.hidden = true;
this.fireEvent("hide", this);
}
if (deep === true && this.parentMenu) {
this.parentMenu.hide(true);
}
}
});
Ext.ux.form.DateTimeField = Ext.extend(Ext.form.DateField, {
dateFormat: 'Y-m-d',
timeFormat: 'H:i:s',
defaultAutoCreate: {
tag: "input",
type: "text",
size: "20",
autocomplete: "off"
},
initComponent: function(){
Ext.ux.form.DateTimeField.superclass.initComponent.call(this);
this.format = this.dateFormat + ' ' + this.timeFormat;
this.afterMethod('afterRender', function(){
this.getEl().applyStyles('top:0');
});
},
getValue: function(){
return this.parseDate(Ext.form.DateField.superclass.getValue.call(this)) || '';
},
onTriggerClick: function(){
if (this.disabled) {
return;
}
if (this.menu == null) {
this.menu = new Ext.menu.DateTimeMenu();
}
Ext.apply(this.menu.picker, {
minDate: this.minValue,
maxDate: this.maxValue,
disabledDatesRE: this.ddMatch,
disabledDatesText: this.disabledDatesText,
disabledDays: this.disabledDays,
disabledDaysText: this.disabledDaysText,
format: this.format,
timeFormat: this.timeFormat,
dateFormat: this.dateFormat,
showToday: this.showToday,
minText: String.format(this.minText, this.formatDate(this.minValue)),
maxText: String.format(this.maxText, this.formatDate(this.maxValue))
});
if (this.menuEvents) {
this.menuEvents('on');
}
else {
this.menu.on(Ext.apply({}, this.menuListeners, {
scope: this
}));
}
this.menu.picker.setValue(this.getValue() || new Date());
this.menu.show(this.el, "tl-bl?");
}
});
Ext.reg('datetimefield', Ext.ux.form.DateTimeField);
~~~
Ext.hoo.form.DateTimeField.js
~~~
/**
* @function 可以选择日期的DateTimeField
* @auhor: hoojo
* @createDate: Sep 16, 2010 9:25:12 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
* @class Ext.hoo.form.DateTimeField
* @extends Ext.ux.form.DateTimeField
*/
Ext.ns("Ext.hoo.form");
Ext.hoo.form.DateTimeField = Ext.extend(Ext.ux.form.DateTimeField, {
constructor: function () {
Ext.hoo.form.DateTimeField.superclass.constructor.call(this, {
renderTo: "show",
height: 222,
dateFormat: 'Y-m-d',
timeFormat: 'H:i:s',
listeners: {
select: function () {
alert(this.getValue() + "##" + this.getRawValue());
}
}
});
}
});
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
Ext.QuickTips.init();
Ext.form.Field.prototype.msgTarget = "qtip";
new Ext.hoo.form.DateTimeField();
});
~~~
### 三、带图标的下列列表
效果图如下
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122a8a7fa.gif)
需要的文件
combo_icon.gif
iconCombobox 插件文件: Ext.ux.IconCombo.js
示例文件: Ext.hoo.form.WebBroserIconComboBox.js
代码如下
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>form Component -- iconCombo</title>
<meta http-equiv="pragma" content="no-cache"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="expires" content="0"/>
<meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="author" content="hoojo"/>
<meta http-equiv="email" content="hoojo_@126.com"/>
<meta http-equiv="ext-lib" content="version 2.2"/>
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>
<link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"/>
<link rel="stylesheet" type="text/css" href="../css/iconCombo.css"/>
<style type="text/css">
.ffCls {
background: url(../images/combo_icon.gif) no-repeat 1px -15px;
}
.ieCls {
background: url(../images/combo_icon.gif) no-repeat 1px 2px;
}
.operaCls {
background: url(../images/combo_icon.gif) no-repeat 1px -68px;
}
.chromeCls {
background: url(../images/combo_icon.gif) no-repeat 1px -85px;
}
.maxCls {
background: url(../images/combo_icon.gif) no-repeat 1px -32px;
}
.ttCls {
background: url(../images/combo_icon.gif) no-repeat 1px -50px;
}
.sfCls {
background: url(../images/combo_icon.gif) no-repeat 1px -103px;
}
.twCls {
background: url(../images/combo_icon.gif) no-repeat 1px -121px;
}
.flockCls {
background: url(../images/combo_icon.gif) no-repeat 1px -139px;
}
</style>
<script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext2/ext-all.js"></script>
<script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="Ext.ux.IconCombo.js"></script>
<script type="text/javascript" src="Ext.hoo.form.WebBroserIconComboBox.js"></script>
</head>
<body>
<div id="show" style="padding: 100px 0 0 300px;"></div>
</body>
</html>
~~~
Ext.ux.IconCombo.js 文件代码
~~~
/**
* @class Ext.ux.IconCombo
* @extends Ext.form.ComboBox
* @param {Object} config Configuration options
*/
Ext.ux.IconCombo = function(config) {
// call parent constructor
Ext.ux.IconCombo.superclass.constructor.call(this, config);
this.tpl = config.tpl || '<tpl for="."><div class="x-combo-list-item">'
+ '<table><tbody><tr>' + '<td>' + '<div class="{'
+ this.iconClsField + '}"></div></td>' + '<td>{'
+ this.displayField + '}</td>' + '</tr></tbody></table>'
+ '</div></tpl>';
};
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
defaultIconCls: "ux-icon-combo-icon",
emptyText: "plase selected",
setIconCls : function() {
var record = this.store.query(this.valueField, this.getValue()).itemAt(0);
if (record) {
this.flag.className = record.get(this.iconClsField) || defaultIconCls || "ux-icon-combo-icon";
//this.flag.style.backgroundImage = rec.get(this.iconClsField);
}
},
setValue : function(value) {
Ext.ux.IconCombo.superclass.setValue.call(this, value);
this.setIconCls();
},
onRender: function(ct, position) {
Ext.ux.IconCombo.superclass.onRender.call(this, ct, position);
var wrap = this.el.up("div.x-form-field-wrap");
this.wrap.applyStyles({
position : "relative"
});
this.el.addClass("ux-icon-combo-input");
//textfield中显示的图片div
this.flag = Ext.DomHelper.append(wrap, {
tag : "div",
style : "position:absolute; left: 5px; top: 1px;"
});
//默认图片样式
this.flag.className = this.defaultIconCls;
}
});
~~~
Ext.hoo.form.WebBroserIconComboBox.js
~~~
/**
* @function 带图片的combobox
* @auhor: hoojo
* @createDate: Sep 10, 2010 11:16:12 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
* @class Ext.hoo.form.WebBroserIconComboBox
* @extends Ext.ux.IconCombo
*/
Ext.ns("Ext.hoo.form");
Ext.hoo.form.WebBroserIconComboBox = Ext.extend(Ext.ux.IconCombo, {
constructor: function () {
Ext.hoo.form.WebBroserIconComboBox.superclass.constructor.call(this, {
/*fieldLabel: "web broser type",
labelWidth: 73,*/
renderTo: /*Ext.getBody(),*/"show",
width: 200,
store: new Ext.data.SimpleStore({
fields: ["shortName", "name", "iconCls"],
data: [
["ff", "Mozilla Firefox" , "ffCls"],
["IE", "Internet Explorer" , "IECls"],
["opera", "Opera" , "operaCls"],
["chrome", "Google Chrome" , "chromeCls"],
["max", "Maxthon" , "maxCls"],
["tt", "TecentTraveler" , "ttCls"],
["sf", "Safari" , "sfCls"],
["tw", "TheWorld" , "twCls"],
["flock", "Flock" , "flockCls"]
]
}),
valueField: "shortName",
displayField: "name",
iconClsField: "iconCls",
triggerAction: "all",
editable: false,
mode: "local"
});
this.on("select", function (field, e) {
alert(field.getValue() + "###" + field.getRawValue());
}, this);
}
});
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
Ext.QuickTips.init();
Ext.form.Field.prototype.msgTarget = "qtip";
new Ext.hoo.form.WebBroserIconComboBox();
});
~~~
### 四、多选下列列表组件
可以同时选择多个选项
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122aab618.gif)
核心文件
多选下拉列表组件:Ext.form.MultiComboBox.js
示例文件:Ext.hoo.form.InterestMultiComboBox.js
代码如下
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>form Component -- MultiComboBox</title>
<meta http-equiv="pragma" content="no-cache"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="expires" content="0"/>
<meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="author" content="hoojo"/>
<meta http-equiv="email" content="hoojo_@126.com"/>
<meta http-equiv="ext-lib" content="version 2.2"/>
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>
<link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"/>
<style type="text/css">
.checked{
background-image: url("../ext2/resources/images/default/menu/checked.gif");
}
.unchecked{
background-image: url("../ext2/resources/images/default/menu/unchecked.gif");
}
.x-combo-list-item {
line-height: 18px;
}
</style>
<script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext2/ext-all.js"></script>
<script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="Ext.form.MultiComboBox.js"></script>
<script type="text/javascript" src="Ext.hoo.form.InterestMultiComboBox.js"></script>
</head>
<body>
<center>
<div id="show" style="padding-top: 200px;"></div>
</center>
</body>
</html>
~~~
Ext.form.MultiComboBox.js
~~~
Ext.form.MultiComboBox = Ext.extend(Ext.form.TriggerField, {
defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
listClass: '',
selectedClass: 'x-combo-selected',
triggerClass : 'x-form-arrow-trigger',
shadow:'sides',
listAlign: 'tl-bl?',
maxHeight: 300,
triggerAction: 'query',
minChars : 4,
typeAhead: false,
queryDelay: 500,
pageSize: 0,
selectOnFocus: false,
queryParam: 'query',
loadingText: 'Loading...',
resizable: false,
handleHeight : 8,
editable: true,
allQuery: '',
mode: 'remote',
minListWidth : 70,
forceSelection:false,
typeAheadDelay : 250,
displaySeparator:';',
valueSeparator:',',
lazyInit : true,
initComponent : function(){
Ext.form.ComboBox.superclass.initComponent.call(this);
this.addEvents(
'expand',
'collapse',
'beforeselect',
'select',
'beforequery'
);
if(this.transform){
this.allowDomMove = false;
var s = Ext.getDom(this.transform);
if(!this.hiddenName){
this.hiddenName = s.name;
}
if(!this.store){
this.mode = 'local';
var d = [], opts = s.options;
for(var i = 0, len = opts.length;i < len; i++){
var o = opts[i];
var value = (Ext.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
if(o.selected) {
this.value = value;
}
d.push([value, o.text]);
}
this.store = new Ext.data.SimpleStore({
'id': 0,
fields: ['value', 'text'],
data : d
});
this.valueField = 'value';
this.displayField = 'text';
}
s.name = Ext.id(); // wipe out the name in case somewhere else they have a reference
if(!this.lazyRender){
this.target = true;
this.el = Ext.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
Ext.removeNode(s); // remove it
this.render(this.el.parentNode);
}else{
Ext.removeNode(s); // remove it
}
}
this.selectedIndex = -1;
if(this.mode == 'local'){
if(this.initialConfig.queryDelay === undefined){
this.queryDelay = 10;
}
if(this.initialConfig.minChars === undefined){
this.minChars = 0;
}
}
},
// private
onRender : function(ct, position){
Ext.form.ComboBox.superclass.onRender.call(this, ct, position);
var disValue="";
if(this.hiddenName){
this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
'before', true);
var hvalue=this.hiddenValue !== undefined ? this.hiddenValue :
this.value !== undefined ? this.value : '';
var hvalueArray=hvalue.split(this.valueSeparator);
for(var i=0;i<this.store.data.length;i++){
var r = this.store.getAt(i);
var newValue = r.data[this.displayField];
var v=r.data[this.valueField];
for(var j=0;j<hvalueArray.length;j++){
if(hvalueArray[j]==v){
disValue+=newValue+this.displaySeparator;
}
}
}
this.hiddenField.value =this.hiddenValue !== undefined ? this.hiddenValue :
this.value !== undefined ? this.value : '';
this.el.dom.removeAttribute('name');
}
if(Ext.isGecko){
this.el.dom.setAttribute('autocomplete', 'off');
}
if(!this.lazyInit){
this.initList();
}else{
this.on('focus', this.initList, this, {single: true});
}
if(!this.editable){
this.editable = true;
this.setEditable(false);
}
this.setValue(disValue);
},
initList : function(){
if(!this.list){
var cls = 'x-combo-list';
this.list = new Ext.Layer({
shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
});
var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
this.list.setWidth(lw);
this.list.swallowEvent('mousewheel');
this.assetHeight = 0;
if(this.title){
this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
this.assetHeight += this.header.getHeight();
}
this.innerList = this.list.createChild({cls:cls+'-inner'});
this.innerList.on('mouseover', this.onViewOver, this);
this.innerList.on('mousemove', this.onViewMove, this);
this.innerList.setWidth(lw - this.list.getFrameWidth('lr'))
if(this.pageSize){
this.footer = this.list.createChild({cls:cls+'-ft'});
this.pageTb = new Ext.PagingToolbar({
store:this.store,
pageSize: this.pageSize,
renderTo:this.footer
});
this.assetHeight += this.footer.getHeight();
}
if(!this.tpl){
//alert(cls);
//x-combo-list-item
this.tpl = '<tpl for="."><div class="'+cls+'-item"><span class="unchecked" style="padding-bottom: 1px;" id="checkBox_{' + this.displayField + '}"> </span>{' + this.displayField + '}</div></tpl>';
}
this.view = new Ext.DataView({
applyTo: this.innerList,
tpl: this.tpl,
singleSelect: true,
selectedClass: this.selectedClass,
itemSelector: this.itemSelector || '.' + cls + '-item'
});
this.view.on('click', this.onViewClick, this);
this.bindStore(this.store, true);
if(this.resizable){
this.resizer = new Ext.Resizable(this.list, {
pinned:true, handles:'se'
});
this.resizer.on('resize', function(r, w, h){
this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
this.listWidth = w;
this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
this.restrictHeight();
}, this);
this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
}
}
},
bindStore : function(store, initial){
if(this.store && !initial){
this.store.un('beforeload', this.onBeforeLoad, this);
this.store.un('load', this.onLoad, this);
this.store.un('loadexception', this.collapse, this);
if(!store){
this.store = null;
if(this.view){
this.view.setStore(null);
}
}
}
if(store){
this.store = Ext.StoreMgr.lookup(store);
this.store.on('beforeload', this.onBeforeLoad, this);
this.store.on('load', this.onLoad, this);
this.store.on('loadexception', this.collapse, this);
if(this.view){
this.view.setStore(store);
}
}
},
// private
initEvents : function(){
Ext.form.ComboBox.superclass.initEvents.call(this);
this.keyNav = new Ext.KeyNav(this.el, {
"up" : function(e){
this.inKeyMode = true;
this.selectPrev();
},
"down" : function(e){
if(!this.isExpanded()){
this.onTriggerClick();
}else{
this.inKeyMode = true;
this.selectNext();
}
},
"enter" : function(e){
this.onViewClick();
//return true;
},
"esc" : function(e){
this.collapse();
},
"tab" : function(e){
this.onViewClick(false);
return true;
},
scope : this,
doRelay : function(foo, bar, hname){
if(hname == 'down' || this.scope.isExpanded()){
return Ext.KeyNav.prototype.doRelay.apply(this, arguments);
}
return true;
},
forceKeyDown : true
});
this.queryDelay = Math.max(this.queryDelay || 10,
this.mode == 'local' ? 10 : 250);
this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);
if(this.typeAhead){
this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this);
}
if(this.editable !== false){
this.el.on("keyup", this.onKeyUp, this);
}
if(this.forceSelection){
this.on('blur', this.doForce, this);
}
},
onDestroy : function(){
if(this.view){
this.view.el.removeAllListeners();
this.view.el.remove();
this.view.purgeListeners();
}
if(this.list){
this.list.destroy();
}
this.bindStore(null);
Ext.form.ComboBox.superclass.onDestroy.call(this);
},
// private
fireKey : function(e){
if(e.isNavKeyPress() && !this.list.isVisible()){
this.fireEvent("specialkey", this, e);
}
},
// private
onResize: function(w, h){
Ext.form.ComboBox.superclass.onResize.apply(this, arguments);
if(this.list && this.listWidth === undefined){
var lw = Math.max(w, this.minListWidth);
this.list.setWidth(lw);
this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
}
},
// private
onDisable: function(){
Ext.form.ComboBox.superclass.onDisable.apply(this, arguments);
if(this.hiddenField){
this.hiddenField.disabled = this.disabled;
}
},
setEditable : function(value){
if(value == this.editable){
return;
}
this.editable = value;
if(!value){
this.el.dom.setAttribute('readOnly', true);
this.el.on('mousedown', this.onTriggerClick, this);
this.el.addClass('x-combo-noedit');
}else{
this.el.dom.setAttribute('readOnly', false);
this.el.un('mousedown', this.onTriggerClick, this);
this.el.removeClass('x-combo-noedit');
}
},
// private
onBeforeLoad : function(){
if(!this.hasFocus){
return;
}
this.innerList.update(this.loadingText ?
'<div class="loading-indicator">'+this.loadingText+'</div>' : '');
this.restrictHeight();
this.selectedIndex = -1;
},
// private
onLoad : function(){
if(!this.hasFocus){
return;
}
if(this.store.getCount() > 0){
this.expand();
this.restrictHeight();
if(this.lastQuery == this.allQuery){
if(this.editable){
this.el.dom.select();
}
if(!this.selectByValue(this.value, true)){
this.select(0, true);
}
}else{
this.selectNext();
if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){
this.taTask.delay(this.typeAheadDelay);
}
}
}else{
this.onEmptyResults();
}
},
// private
onTypeAhead : function(){
if(this.store.getCount() > 0){
var r = this.store.getAt(0);
var newValue = r.data[this.displayField];
var len = newValue.length;
var selStart = this.getRawValue().length;
if(selStart != len){
this.setRawValue(newValue);
this.selectText(selStart, newValue.length);
}
}
},
// private
onSelect : function(record, index){
if(this.fireEvent('beforeselect', this, record, index) !== false){
var r = this.store.getAt(index);
var newValue = r.data[this.displayField];
var check=document.getElementById("checkBox_"+newValue);
if(check.className=="checked"){
check.className="unchecked"
}else{
check.className="checked"
}
var value="";
var hiddenValue="";
for(var i=0;i<this.store.data.length;i++){
var r = this.store.getAt(i);
newValue = r.data[this.displayField];
check=document.getElementById("checkBox_"+newValue);
if(check.className=="checked"){
value+= r.data[this.displayField]+this.displaySeparator;
hiddenValue+= r.data[this.valueField]+this.valueSeparator;
}
}
if(value.length>1){
value=value.substring(0,value.length-this.displaySeparator.length);
}
if(hiddenValue.length>1){
hiddenValue=hiddenValue.substring(0,value.length-this.valueSeparator.length);
}
this.setValue(value);
this.hiddenField.value=hiddenValue;
this.fireEvent('select', this, record, index);
}
},
getValue : function(){
if(this.valueField){
return typeof this.value != 'undefined' ? this.value : '';
}else{
return Ext.form.ComboBox.superclass.getValue.call(this);
}
},
/**
* Clears any text/value currently set in the field
*/
clearValue : function(){
if(this.hiddenField){
this.hiddenField.value = '';
}
this.setRawValue('');
this.lastSelectionText = '';
this.applyEmptyText();
},
setValue : function(v){
var text = v;
if(this.valueField){
var r = this.findRecord(this.valueField, v);
if(r){
text = r.data[this.displayField];
}else if(this.valueNotFoundText !== undefined){
text = this.valueNotFoundText;
}
}
this.lastSelectionText = text;
Ext.form.ComboBox.superclass.setValue.call(this, text);
this.value = v;
},
// private
findRecord : function(prop, value){
var record;
if(this.store.getCount() > 0){
this.store.each(function(r){
if(r.data[prop] == value){
record = r;
return false;
}
});
}
return record;
},
// private
onViewMove : function(e, t){
this.inKeyMode = false;
},
// private
onViewOver : function(e, t){
if(this.inKeyMode){ // prevent key nav and mouse over conflicts
return;
}
var item = this.view.findItemFromChild(t);
if(item){
var index = this.view.indexOf(item);
this.select(index, false);
}
},
// private
onViewClick : function(doFocus){
var index = this.view.getSelectedIndexes()[0];
var r = this.store.getAt(index);
if(r){
this.onSelect(r, index);
}
if(doFocus !== false){
this.el.focus();
}
},
// private
restrictHeight : function(){
this.innerList.dom.style.height = '';
var inner = this.innerList.dom;
var fw = this.list.getFrameWidth('tb');
var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
this.list.beginUpdate();
this.list.setHeight(this.innerList.getHeight()+fw+(this.resizable?this.handleHeight:0)+this.assetHeight);
this.list.alignTo(this.el, this.listAlign);
this.list.endUpdate();
},
// private
onEmptyResults : function(){
this.collapse();
},
/**
* Returns true if the dropdown list is expanded, else false.
*/
isExpanded : function(){
return this.list && this.list.isVisible();
},
selectByValue : function(v, scrollIntoView){
if(v !== undefined && v !== null){
var r = this.findRecord(this.valueField || this.displayField, v);
if(r){
this.select(this.store.indexOf(r), scrollIntoView);
return true;
}
}
return false;
},
select : function(index, scrollIntoView){
this.selectedIndex = index;
this.view.select(index);
if(scrollIntoView !== false){
var el = this.view.getNode(index);
if(el){
this.innerList.scrollChildIntoView(el, false);
}
}
},
// private
selectNext : function(){
var ct = this.store.getCount();
if(ct > 0){
if(this.selectedIndex == -1){
this.select(0);
}else if(this.selectedIndex < ct-1){
this.select(this.selectedIndex+1);
}
}
},
// private
selectPrev : function(){
var ct = this.store.getCount();
if(ct > 0){
if(this.selectedIndex == -1){
this.select(0);
}else if(this.selectedIndex != 0){
this.select(this.selectedIndex-1);
}
}
},
// private
onKeyUp : function(e){
if(this.editable !== false && !e.isSpecialKey()){
this.lastKey = e.getKey();
this.dqTask.delay(this.queryDelay);
}
},
// private
validateBlur : function(){
return !this.list || !this.list.isVisible();
},
// private
initQuery : function(){
this.doQuery(this.getRawValue());
},
// private
doForce : function(){
if(this.el.dom.value.length > 0){
this.el.dom.value =
this.lastSelectionText === undefined ? '' : this.lastSelectionText;
this.applyEmptyText();
}
},
doQuery : function(q, forceAll){
if(q === undefined || q === null){
q = '';
}
var qe = {
query: q,
forceAll: forceAll,
combo: this,
cancel:false
};
if(this.fireEvent('beforequery', qe)===false || qe.cancel){
return false;
}
q = qe.query;
forceAll = qe.forceAll;
if(forceAll === true || (q.length >= this.minChars)){
if(this.lastQuery !== q){
this.lastQuery = q;
if(this.mode == 'local'){
this.selectedIndex = -1;
if(forceAll){
this.store.clearFilter();
}else{
this.store.filter(this.displayField, q);
}
this.onLoad();
}else{
this.store.baseParams[this.queryParam] = q;
this.store.load({
params: this.getParams(q)
});
this.expand();
}
}else{
this.selectedIndex = -1;
this.onLoad();
}
}
},
// private
getParams : function(q){
var p = {};
//p[this.queryParam] = q;
if(this.pageSize){
p.start = 0;
p.limit = this.pageSize;
}
return p;
},
/**
* Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
*/
collapse : function(){
if(!this.isExpanded()){
return;
}
this.list.hide();
Ext.getDoc().un('mousewheel', this.collapseIf, this);
Ext.getDoc().un('mousedown', this.collapseIf, this);
this.fireEvent('collapse', this);
},
// private
collapseIf : function(e){
if(!e.within(this.wrap) && !e.within(this.list)){
this.collapse();
}
},
/**
* Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
*/
expand : function(){
if(this.isExpanded() || !this.hasFocus){
return;
}
this.list.alignTo(this.wrap, this.listAlign);
var hvalueArray=this.hiddenField.value.split(this.valueSeparator);
for(var i=0;i<this.store.data.length;i++){
var r = this.store.getAt(i);
var newValue = r.data[this.displayField];
var v=r.data[this.valueField];
for(var j=0;j<hvalueArray.length;j++){
if(hvalueArray[j]==v){
document.getElementById("checkBox_"+newValue).className="checked";
}
}
}
this.list.show();
Ext.getDoc().on('mousewheel', this.collapseIf, this);
Ext.getDoc().on('mousedown', this.collapseIf, this);
this.fireEvent('expand', this);
},
// private
// Implements the default empty TriggerField.onTriggerClick function
onTriggerClick : function(){
if(this.disabled){
return;
}
if(this.isExpanded()){
this.collapse();
this.el.focus();
}else {
this.onFocus({});
if(this.triggerAction == 'all') {
this.doQuery(this.allQuery, true);
} else {
this.doQuery(this.getRawValue());
}
this.el.focus();
}
}
});
Ext.reg('multicombo', Ext.form.MultiComboBox);
~~~
Ext.hoo.form.InterestMultiComboBox.js
~~~
/**
* @function 支持多选的combox
* @auhor: hoojo
* @createDate: Sep 10, 2010 10:32:00 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
* @class Ext.hoo.form.InterestMultiComboBox
* @extends Ext.form.MultiComboBox
*/
Ext.ns("Ext.hoo.form");
Ext.hoo.form.InterestMultiComboBox = Ext.extend(Ext.form.MultiComboBox, {
constructor: function () {
Ext.hoo.form.InterestMultiComboBox.superclass.constructor.call(this, {
renderTo: "show",
width: 250,
mode: "local",
fieldLabel: "多选下拉框",
store: new Ext.data.SimpleStore({
fields: ["textAttr", "valueAttr"],
data: [
["打球", "batting"],
["看书", "lookbook"],
["睡觉", "sleeping"],
["购物", "shopping"],
["打游戏", "games"],
["唱歌", "sing"]
]
}),
editable: true,
emptyText:"请选择",
//allowBlank: false,
valueField: "textAttr",
displayField: "valueAttr",
labelSeparator: ":",
valueSeparator: "#",
displaySeparator: ",",
//value:"batting,sleeping",
hiddenName: "interest",
forceSelection: true,
triggerAction: "all"
});
this.on("select", function (field, record, index) {
alert(field.getValue() + "%%%%" + field.getRawValue() + Ext.fly("interest").dom.value);
}, this);
}
});
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
Ext.QuickTips.init();
Ext.form.Field.prototype.msgTarget = "qtip";
new Ext.hoo.form.InterestMultiComboBox();
});
~~~
### 五、动态Combobox Tree(下拉列表树)组件
可以多选、单选、checkbox
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122acf8b3.gif)
需要的文件
动态下列列表树插件:Ext.ux.form.DynamicTreeCombox.js
示例文件:Ext.hoo.form.DynaTreeCombo.js
代码如下:
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>form Component -- MultiComboBox</title>
<meta http-equiv="pragma" content="no-cache"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="expires" content="0"/>
<meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="author" content="hoojo"/>
<meta http-equiv="email" content="hoojo_@126.com"/>
<meta http-equiv="ext-lib" content="version 2.2"/>
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>
<link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"/>
<script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext2/ext-all.js"></script>
<script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="Ext.ux.form.DynamicTreeCombox.js"></script>
<script type="text/javascript" src="Ext.hoo.form.DynaTreeCombo.js"></script>
</head>
<body>
<div id="show" style="float: left; margin: 100px 0 0 100px;"></div>
<div id="showBasic" style="float: left; margin: 100px 0 0 100px;"></div>
<div id="showConstom" style="float: left; margin: 100px 0 0 100px;"></div>
</body>
</html>
~~~
Ext.ux.form.DynamicTreeCombox.js
~~~
Ext.ns("Ext.ux.form");
Ext.ux.form.DynamicTreeCombox = Ext.extend(Ext.form.ComboBox, {
initComponent:function(){
Ext.ux.form.DynamicTreeCombox.superclass.initComponent.call(this);
this.addEvents('beforeClickNode','afterClickNode', 'select');
if(!this.tree){
var root = this.root || new Ext.tree.AsyncTreeNode();
this.tree = new Ext.tree.TreePanel({
containerScroll: true,
rootVisible: false,
border: false,
root: root
});
this.tree.loader = new Ext.tree.TreeLoader(this.loaderConfig||{dataUrl:"",baseAttrs:{}});
this.tree.loader.addListener("beforeload",this.beforeLoad,this);
this.tree.loader.addListener("load",this.onLoad,this);
this.tree.addListener('collapsenode',this.onNodeCollapse,this);
this.tree.addListener('expandnode',this.onNodeExpand,this);
}
var fieldMp = {
text: "text",
qtip: "qtip",
parentFuncId: "id",
icon: "icon"
};
if(!this.fieldMapping){
this.fieldMapping = fieldMp;
}else{
Ext.applyIf(this.fieldMapping, fieldMp);
}
},
initList:function(){
if(!this.list){
var cls = 'x-combo-list';
this.list = new Ext.Layer({
shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
});
var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
this.list.setWidth(lw);
this.list.swallowEvent('mousewheel');
this.innerList = this.list.createChild({cls:cls+'-inner'});
this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
this.innerList.setHeight("100%");
}
},
doQuery:function(){
if(this.expandAll){
var loader=this.tree.loader;
if(loader.baseAttrs){
Ext.apply(loader.baseAttrs,{expanded:this.expandAll});
}else{
loader.baseAttrs={expanded:this.expandAll};
}
}
if(!this.tree.rendered){
this.tree.render(this.innerList);
this.tree.addListener("click",this.clickNode,this);
}
this.expand();
},
beforeLoad:function(loader,node){
if(node!=node.getOwnerTree().root){
loader.baseParams.parentFuncId=node.attributes[this.fieldMapping.parentFuncId];
}
},
onLoad:function(loader,node,res){
var nodeArr=node.childNodes;
for(var i=0,j=nodeArr.length;i<j;i++){
if(nodeArr[i].attributes[this.fieldMapping.icon]){
nodeArr[i].getUI().getIconEl().src=nodeArr[i].attributes[this.fieldMapping.icon];
}
nodeArr[i].setText(nodeArr[i].attributes[this.fieldMapping.text]);
nodeArr[i].ui.textNode.setAttribute("qtip", nodeArr[i].attributes[this.fieldMapping.qtip]);
}
},
clickNode:function(node){
if(this.fireEvent('beforeClickNode',this,node)){
this.setValue(node.attributes[this.displayField]);
this.value = node.attributes[this.valField || "id"];
}
this.fireEvent("afterClickNode",this,node);
this.fireEvent("select",this,node);
this.collapse();
},
onNodeCollapse:function(node){
this.list.setHeight(this.tree.getEl().getHeight()+2);
},
getValue: function () {
return this.value;
},
onNodeExpand:function(node){
this.list.setHeight(this.tree.getEl().getHeight()+2);
},
onDestroy:function(){
if(this.view){
this.view.el.removeAllListeners();
this.view.el.remove();
this.view.purgeListeners();
}
if(this.tree.loader){
this.tree.loader.purgeListeners();
}
if(this.tree){
this.tree.el.removeAllListerers();
this.tree.el.remove();
this.tree.purgeListeners();
}
if(this.innerList){
this.innerList.destroy();
}
if(this.list){
this.list.destroy();
}
Ext.form.ComboBox.superclass.onDestroy.call(this);
}
});
Ext.reg("treecombox",Ext.ux.form.DynamicTreeCombox);
~~~
Ext.hoo.form.DynaTreeCombo.js
~~~
/**
* @function 动态tree的combobox,本地数据
* @auhor: hoojo
* @createDate: Sep 11, 2010 6:33:13 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
* @class Ext.hoo.form.DynaTreeCombo
* @extends Ext.ux.form.DynamicTreeCombox
*/
Ext.ns("Ext.hoo.form");
Ext.hoo.form.DynaTreeCombo = Ext.extend(Ext.ux.form.DynamicTreeCombox, {
constructor: function () {
Ext.hoo.form.DynaTreeCombo.superclass.constructor.call(this, {
renderTo: "show",
expandAll: false,
readOnly: true,
width: 200,
displayField: "text",
valField: "id",
root: new Ext.tree.AsyncTreeNode({
text: "ExtJS",
id: "0",
children: [{
text: "adpter",
qtip: "这是一个adpter的tip",
children: [{
text: "ext",
leaf: true,
qtip: "这是一个ext的tip",
checked: true
},{
text: "yui",
leaf: true
},{
text: "jquery",
leaf: true
},{
text: "prototype",
leaf: true,
checked: false
}]
},{
text: "air",
checked: false,
children: [{
text: "air.jsb",
leaf: true
},{
text: "ext-air.js",
leaf: true
}]
},{
text: "docs"
}]
})
});
this.on("select", function (field, node) {
alert(field.getValue() + "###" + field.getRawValue() + "##" + node.text);
}, this);
this.on("check", function (field, node) {
alert(field.getValue() + "###" + field.getRawValue() + "##" + node.text);
}, this);
}
});
/**
* @function DynamicTreeCombox 后台数据
* @auhor: hoojo
* @createDate: Sep 11, 2010 10:30:27 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
*/
Ext.hoo.form.AsyncBasicDynaTreeCombo = Ext.extend(Ext.ux.form.DynamicTreeCombox, {
constructor: function () {
Ext.hoo.form.AsyncBasicDynaTreeCombo.superclass.constructor.call(this, {
renderTo: "showBasic",
expandAll: false,
readOnly: true,
width: 200,
displayField: "text",
valField: "id",
loaderConfig:{
dataUrl: "../ServiceDataServlet?method=basic"//加载树的URL
}
});
this.on("select", function (field, node) {
alert(field.getValue() + "###" + field.getRawValue() + "##" + node.text);
}, this);
}
});
/**
* @function 后台数据
* @auhor: hoojo
* @createDate: Sep 11, 2010 10:30:59 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
*/
Ext.hoo.form.AsyncConstomDynaTreeCombo = Ext.extend(Ext.ux.form.DynamicTreeCombox, {
constructor: function () {
Ext.hoo.form.AsyncConstomDynaTreeCombo.superclass.constructor.call(this, {
renderTo: "showConstom",
expandAll: false,
readOnly: true,
width: 200,
displayField: "text",
valField: "id",
loaderConfig:{
dataUrl: "../ServiceDataServlet?method=constom",
baseParams:{parentFuncId:""}//如果传递parentFuncId就会查询当前id下的节点
},
//后台数据中没有text、qtip、icon、parentFuncId属性,需加上fieldMapping进行属性映射,如果后台返回数据中有此属性可省略
fieldMapping: {
text: "text",//映射node的text字段
qtip: "tip",//映射node的qtip字段
parentFuncId: "text"//映射动态请求后台的text属性作为请求参数
//icon: "img"
}
});
this.on("select", function (field, node) {
alert(field.getValue() + "###" + field.getRawValue() + "##" + node.text);
}, this);
}
});
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
Ext.QuickTips.init();
Ext.form.Field.prototype.msgTarget = "qtip";
new Ext.hoo.form.DynaTreeCombo();
new Ext.hoo.form.AsyncBasicDynaTreeCombo();
new Ext.hoo.form.AsyncConstomDynaTreeCombo();
});
~~~
ServiceDataServlet.java
~~~
package com.hoo.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServiceDataServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/json");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
String method = request.getParameter("method");
StringBuilder sb = new StringBuilder();
if ("basic".equals(method)) {
sb.append("[")
.append("{").append("text:\"").append("adpter").append("\", qtip: \"").append("qtip提示:ADPTER").append("\",");
sb.append("children: [")
.append("{").append("text:\"").append("ext").append("\", qtip: \"").append("qtip提示:ext").append("\",")
.append("leaf: true").append("},")
.append("{").append("text:\"").append("jquery")
.append("\",").append("leaf: true").append("}]").append("},")
.append("{").append("text:\"").append("air").append("\",");
sb.append("children: [")
.append("{").append("text:\"").append("air.jsb")
.append("\",").append("leaf: true").append("},")
.append("{").append("text:\"").append("ext-air.js")
.append("\",").append("leaf: true").append("}]").append("},")
.append("{").append("text:\"").append("readMe.text").append("\",")
.append("leaf: true}");
sb.append("]");
}
if ("constom".equals(method)) {
sb.append("[")
.append("{").append("text:\"").append("adpter").append("\", tip: \"").append("ADPTER").append("\",");
sb.append("children:[")
.append("{").append("text:\"").append("ext").append("\", tip: \"").append("EXT").append("\",")
.append("leaf: true").append("},")
.append("{").append("text:\"").append("jquery").append("\", tip: \"").append("JQUERY").append("\",")
.append("leaf: true").append("}]},")
.append("{").append("text:\"").append("air").append("\", tip: \"").append("AIR").append("\",");
sb.append("children:[")
.append("{").append("text:\"").append("air.jsb").append("\", tip: \"").append("AIR.JSB").append("\",")
.append("leaf: true").append("},")
.append("{").append("text:\"").append("ext-air.js").append("\", tip: \"").append("EXT-AIR.JS").append("\",")
.append("leaf: true").append("}]").append("},")
.append("{").append("text:\"").append("readMe.text").append("\", tip: \"").append("README.TEXT").append("\",")
.append("leaf: true}");
sb.append("]");
}
out.print(sb.toString());
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
Struts2、Spring3、MyBatis3整合ExtJS,完成CheckNodeColumnTree
最后更新于:2022-04-01 12:01:24
前面介绍了ColumnTree:[http://www.cnblogs.com/hoojo/archive/2011/05/11/2043426.html](http://www.cnblogs.com/hoojo/archive/2011/05/11/2043426.html "http://www.cnblogs.com/hoojo/archive/2011/05/11/2043426.html")
[http://www.cnblogs.com/hoojo/archive/2011/05/11/2043453.html](http://www.cnblogs.com/hoojo/archive/2011/05/11/2043453.html "http://www.cnblogs.com/hoojo/archive/2011/05/11/2043453.html")
加入CheckNodeColumnTree
A、首先在AccountAction中添加如下代码:
~~~
private String jsonText;
public String getJsonText() {
return jsonText;
}
public String checkNodeColumnTreeData() throws Exception {
jsonText = JSONUtil.serialize(results);
//ServletActionContext.getResponse().getWriter().print(jsonText);
return "showData";
}
~~~
我们不直接使用Servlet的response方法,这样会使Action耦合Servlet的API。我们直接在Action中提供一个jsonText的属性,给该属性提供getter方法。然后当执行checkNodeColumnTreeData这个方法的时候,为jsonText赋值。等待请求成功,跳转到showData的视图中直接去取jsonText的值即可。
B、看看struts.xml中的配置
~~~
<action name="account" class="accountAction">
<result type="redirect">account!show.action</result>
<result name="show">/show.jsp</result>
<result name="showData">/showData.jsp</result>
<result name="tree" type="json">
<param name="excludeProperties">acc</param>
<param name="contentType">text/html</param>
</result>
</action>
~~~
就配置一个result就可以了,跳转到showData页面
C、下面看看showData页面
~~~
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" contentType="text/text; charset=UTF-8"%>
${jsonText}
~~~
代码比较简单,设置下页面才contentType、然后用el表达式取出jsonText的值即可。
D、下面看看CheckNodeColumnTree代码
Ext.hoo.tree.UserCheckNodeColumnTree.js
~~~
/**
* @function CheckNode ColumnTree 多列信息的tree
* @auhor: hoojo
* @createDate: Aug 29, 2010 10:39:02 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
*/
Ext.ns("Ext.hoo.tree");
Ext.hoo.tree.UserCheckNodeColumnTree = Ext.extend(Ext.tree.ColumnTree, {
constructor: function () {
Ext.hoo.tree.UserCheckNodeColumnTree.superclass.constructor.call(this, {
renderTo: "show",
title: "远程数据",
width: 600,
hieght: 400,
autoScroll: true,
rootVisible: true,
checkModel: 'cascade',//级联多选,如果不需要checkbox,该属性去掉
onlyLeafCheckable: false,//所有结点可选,如果不需要checkbox,该属性去掉
columns: [{
header: "编号",
width: 100,
dataIndex: "accountId"
}, {
header: "用户名称",
width: 100,
dataIndex: "username"
}, {
header: "密码",
width: 100,
dataIndex: "password"
}, {
header: "创建时间",
width: 150,
dataIndex: "createTime"
}],
loader: new Ext.tree.TreeLoader({
dataUrl: Ext.hoo.tree.UserCheckNodeColumnTree.TREE_DATA_URL,
clearOnLoad: false,
baseAttrs: {
uiProvider: Ext.ux.ColumnTreeCheckNodeUI,
leaf: true
}
}),
root: new Ext.tree.AsyncTreeNode({
text: "用户基本信息",
id: "root"
})
});
}
});
Ext.hoo.tree.UserCheckNodeColumnTree.TREE_DATA_URL = "account!checkNodeColumnTreeData.action";
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "ext2/resources/images/default/s.gif";
new Ext.hoo.tree.UserCheckNodeColumnTree();
});
~~~
在webroot目录的jslib中加入这个文件Ext.hoo.tree.UserCheckNodeColumnTree.js,然后导入到html中即可。
E、上面的代码用到了Ext.ux.ColumnTreeCheckNodeUI这个UI,我们需要加入这个UI文件Ext.tree.ColumnTreeCheckNodeUI.js,代码如下:
~~~
/*
* Ext JS Library 2.0
* Copyright(c) 2006-2007, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
Ext.tree.ColumnTree = Ext.extend(Ext.tree.TreePanel, {
//lines:false,
borderWidth: Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
cls:'x-column-tree',
scrollOffset : 18,
onRender : function(){
Ext.tree.ColumnTree.superclass.onRender.apply(this, arguments);
this.headers = this.body.createChild(
{cls:'x-tree-headers '},this.body.dom);
var cols = this.columns, c;
var totalWidth = 0;
for(var i = 0, len = cols.length; i < len; i++){
c = cols[i];
totalWidth += c.width;
this.headers.createChild({
cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
cn: {
cls:'x-tree-hd-text',
html: c.header
},
style:'width:'+(c.width-this.borderWidth)+'px;'
});
}
this.headers.createChild({
cls:'x-tree-hd ',
cn: {
html: ''
},
style:'width:'+this.scrollOffset+'px;'
});
totalWidth += this.scrollOffset;
this.headers.createChild({cls:'x-clear'});
// prevent floats from wrapping when clipped
this.headers.setWidth(totalWidth);
totalWidth -= this.scrollOffset;
this.innerCt.setWidth(totalWidth);
}
});
Ext.tree.ColumnTreeNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
focus: Ext.emptyFn, // prevent odd scrolling behavior
renderElements : function(n, a, targetNode, bulkRender){
this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
var t = n.getOwnerTree();
var cols = t.columns;
var bw = t.borderWidth;
var c = cols[0];
var cb = typeof a.checked == 'boolean';
if(typeof this.checkModel != 'undefined'){
cb = (!this.onlyLeafCheckable || n.isLeaf());
}
var href = a.href ? a.href : Ext.isGecko ? "" : "#";
var buf = ['<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">',
'<div class="x-tree-col" style="width:',c.width-bw,'px;">',
'<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
'<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow">',
'<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on">',
cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '',
'<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ',
a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '>',
'<span unselectable="on">', n.text || (a[c.dataIndex]?(c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]):'')," </span></a>",
"</div>"];
for(var i = 1, len = cols.length; i < len; i++){
c = cols[i];
buf.push('<div class="x-tree-col ',(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
'<div class="x-tree-col-text">',(a[c.dataIndex]?(c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]):'')," </div>",
"</div>");
}
buf.push('<div class="x-clear"></div>',
'</div>',
'<ul class="x-tree-node-ct" style="display:none;"></ul>',
"</li>");
if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
this.wrap = Ext.DomHelper.insertHtml("beforeBegin",n.nextSibling.ui.getEl(), buf.join(""));
}else{
this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
}
this.elNode = this.wrap.childNodes[0];
this.ctNode = this.wrap.childNodes[1];
var cs = this.elNode.firstChild.childNodes;
this.indentNode = cs[0];
this.ecNode = cs[1];
this.iconNode = cs[2];
var index = 3;
if(cb){
this.checkbox = cs[3];
index++;
}
this.anchor = cs[index];
this.textNode = cs[index].firstChild;
}
});
Ext.ux.ColumnTreeCheckNodeUI = function() {
//多选: 'multiple'(默认)
//单选: 'single'
//级联多选: 'cascade'(同时选父和子);'parentCascade'(选父);'childCascade'(选子)
this.checkModel = 'multiple';
//only leaf can checked
this.onlyLeafCheckable = false;
Ext.ux.ColumnTreeCheckNodeUI.superclass.constructor.apply(this, arguments);
};
Ext.extend(Ext.ux.ColumnTreeCheckNodeUI, Ext.tree.ColumnTreeNodeUI, {
renderElements : function(n, a, targetNode, bulkRender){
var t = n.getOwnerTree();
this.checkModel = t.checkModel || this.checkModel;
this.onlyLeafCheckable = t.onlyLeafCheckable || false;
Ext.ux.ColumnTreeCheckNodeUI.superclass.renderElements.apply(this, arguments);
var cb = (!this.onlyLeafCheckable || n.isLeaf());
if(cb){
Ext.fly(this.checkbox).on('click', this.check.createDelegate(this,[null]));
}
},
// private
check : function(checked){
var n = this.node;
var tree = n.getOwnerTree();
this.checkModel = tree.checkModel || this.checkModel;
if( checked === null ) {
checked = this.checkbox.checked;
} else {
this.checkbox.checked = checked;
}
n.attributes.checked = checked;
tree.fireEvent('check', n, checked);
if(!this.onlyLeafCheckable){
if(this.checkModel == 'cascade' || this.checkModel == 'parentCascade'){
var parentNode = n.parentNode;
if(parentNode !== null) {
this.parentCheck(parentNode,checked);
}
}
if(this.checkModel == 'cascade' || this.checkModel == 'childCascade'){
if( !n.expanded && !n.childrenRendered ) {
n.expand(false,false,this.childCheck);
}else {
this.childCheck(n);
}
}
} else if(this.checkModel == 'single'){
var checkedNodes = tree.getChecked();
for(var i=0;i<checkedNodes.length;i++){
var node = checkedNodes[i];
if(node.id != n.id){
node.getUI().checkbox.checked = false;
node.attributes.checked = false;
tree.fireEvent('check', node, false);
}
}
}
},
// private
childCheck : function(node){
var a = node.attributes;
if(!a.leaf) {
var cs = node.childNodes;
var csui;
for(var i = 0; i < cs.length; i++) {
csui = cs[i].getUI();
if(csui.checkbox.checked ^ a.checked)
csui.check(a.checked);
}
}
},
// private
parentCheck : function(node ,checked){
var checkbox = node.getUI().checkbox;
if(typeof checkbox == 'undefined')return ;
if(!(checked ^ checkbox.checked))return;
if(!checked && this.childHasChecked(node))return;
checkbox.checked = checked;
node.attributes.checked = checked;
node.getOwnerTree().fireEvent('check', node, checked);
var parentNode = node.parentNode;
if( parentNode !== null){
this.parentCheck(parentNode,checked);
}
},
// private
childHasChecked : function(node){
var childNodes = node.childNodes;
if(childNodes || childNodes.length>0){
for(var i=0;i<childNodes.length;i++){
if(childNodes[i].getUI().checkbox.checked)
return true;
}
}
return false;
},
toggleCheck : function(value){
var cb = this.checkbox;
if(cb){
var checked = (value === undefined ? !cb.checked : value);
this.check(checked);
}
}
});
~~~
F、在html页面中导入这些js库即可运行示例
~~~
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>UserCheckNodeColumnTree 示例</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta http-equiv="author" content="hoojo"/>
<meta http-equiv="email" content="hoojo_@126.com"/>
<meta http-equiv="ext-lib" content="verson 2.2"/>
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>
<meta http-equiv="blog" content="http://hoojo.cnblogs.com"/>
<link rel="stylesheet" type="text/css" href="ext2/resources/css/ext-all.css" />
<link rel="stylesheet" type="text/css" href="jslib/column-tree.css" />
<script type="text/javascript" src="ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext2/ext-all.js"></script>
<script type="text/javascript" src="ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="jslib/Ext.tree.ColumnTreeCheckNodeUI.js"></script>
<script type="text/javascript" src="jslib/Ext.hoo.tree.UserCheckNodeColumnTree.js"></script>
</head>
<body>
<div id="show" style="margin-left: 200px; margin-top: 50px;"></div>
</body>
</html>
~~~
运行后,效果如下:
[![clip_image002](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe1229ae1b0.gif "clip_image002")](http://hi.csdn.net/attachment/201105/12/0_1305176238y2Pk.gif)
如果有子节点的话,可以选择、展开子节点
Struts2、Spring3、MyBatis3整合ExtJS,完成ColumnTree 【二】
最后更新于:2022-04-01 12:01:21
###三、加入Struts2框架
1、 准备工作
添加jar文件如下:
[![clip_image002](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe1228ec445.gif "clip_image002")](http://hi.csdn.net/attachment/201105/11/0_13051072424eVp.gif)
org.springframework.web-3.0.5.RELEASE.jar
org.springframework.aop-3.0.5.RELEASE.jar
这2个jar包是spring的context所依赖的jar包
struts2-spring-plugin-2.2.3.jar是struts整合spring的jar包
2、 在web.xml加入struts2的控制器
~~~
<filter>
<filter-name>struts2filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcherfilter-class>
filter>
<filter-mapping>
<filter-name>struts2filter-name>
<url-pattern>/*url-pattern>
<filter-mapping>
~~~
3、 在src目录添加struts.xml
~~~
<xml version="1.0" encoding="UTF-8"?>
DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.i18n.encoding" value="UTF-8"/>
<package name="ssMyBatis" extends="struts-default">
<package>
<struts>
~~~
启动后,可以看到首页index的页面就基本整合完成。
4、 首先看看Action代码,代码如下:
~~~
package com.hoo.action;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import org.springframework.stereotype.Component;
import com.hoo.biz.AccountBiz;
import com.hoo.entity.Account;
import com.opensymphony.xwork2.ActionSupport;
/**
* function: Account Action
* @author hoojo
* @createDate 2011-5-11 下午12:03:05
* @file AccountAction.java
* @package com.hoo.action
* @project S2SMyBatis
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
@Component
public class AccountAction extends ActionSupport {
/**
* @author Hoojo
*/
private static final long serialVersionUID = -973535478139284399L;
@Inject
@Named("accountBiz")
private AccountBiz<Account> biz;
private Account acc;
private List<Account> results = new ArrayList<Account>();
public List<Account> getResults() {
return results;
}
public Account getAcc() {
return acc;
}
public void setAcc(Account acc) {
this.acc = acc;
}
public String add() throws Exception {
if (!biz.addAccount(acc)) {
this.addActionMessage("添加数据失败");
return ERROR;
}
return SUCCESS;
}
public String show() throws Exception {
results = biz.getList();
return "show";
}
public String remove() throws Exception {
return SUCCESS;
}
public String edit() throws Exception {
return SUCCESS;
}
public String treeData() throws Exception {
results = biz.getList();
return "tree";
}
}
~~~
这个Action被注解成Component,那么在spring的applicationContext配置文件中就不需要进行标签的配置了。上面注入了AccountDao,完成相关操作。
5、 由于Struts2要和Spring进行整合,所以struts的配置会有点不同
~~~
<action name="account" class="accountAction">
<result type="redirect">account!show.actionresult>
<result name="show">/show.jspresult>
<action>
~~~
上面的class不再是AccountAction的classpath,而是spring容器中配置的bean。就是通过@Component注解过的AccountAction,被注解注释过后它的id默认是类名称首字母小写。所以上面的action的配置是accountAction。
6、 由于要整合ExtJS,所以这里用到struts2-json-plugin-2.2.3.jar这个插件,将其加入到lib库中,struts.xml更改成:
~~~
<xml version="1.0" encoding="UTF-8"?>
<DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.i18n.encoding" value="UTF-8"/>
<package name="ssMyBatis" extends="json-default">
<global-results>
<result name="error">/error.jspresult>
<global-results>
<action name="account" class="accountAction">
<result type="redirect">account!show.actionresult>
<result name="show">/show.jspresult>
<result name="tree" type="json">
<param name="excludeProperties">accparam>
<result>
<action>
<package>
<struts>
~~~
AccountAction中的treeData方法返回的tree,在account这个action配置中找到tree的result,将result的type配置成json。表示该result的数据以json的方式展示。tree这个result还配置了一个param,名称为excludeProperties表示排除的属性。这个参数将排除当前Action中的acc属性。也就是说这个属性将不会得到json的转换。其他属性将会被转换成json。
7、 前台页面
index.jsp
~~~
<body>
<a href="account!show.action">显示所有a> <br>
<a href="add.jsp">添加数据a><br/>
<a href="account!treeData.action">JSONa><br/>
<body>
~~~
show.jsp
~~~
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>show all data</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<s:iterator value="results" status="s" var="data">
${data }<===>
<s:property value="#data.accountId"/>#
<s:property value="#data.username"/>#
<s:property value="#data.password"/>#
<s:property value="#data.createTime" />#
<s:date name="#data.createTime" format="yyyy-MM-dd"/>#
<a href="account!remove.action">删除</a> | <a href="account!edit.action">修改</a>
<br/>
</s:iterator>
</body>
</html>
~~~
Struts标签和OGNL表达式显示数据
add.jsp
~~~
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>add</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<s:form action="account!add.action" method="post">
<s:textfield name="acc.username"/>
<s:password name="acc.password"/>
<s:submit value="提交"></s:submit>
</s:form>
</body>
</html>
~~~
###四、整合ExtJS
1、添加ext的库,版本是2.2.2
需要添加column-tree.css
~~~
/*
* Ext JS Library 2.2.1
* Copyright(c) 2006-2009, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
.x-column-tree .x-tree-node {
zoom:1;
}
.x-column-tree .x-tree-node-el {
/*border-bottom:1px solid #eee; borders? */
zoom:1;
}
.x-column-tree .x-tree-selected {
background: #d9e8fb;
}
.x-column-tree .x-tree-node a {
line-height:18px;
vertical-align:middle;
}
.x-column-tree .x-tree-node a span{
}
.x-column-tree .x-tree-node .x-tree-selected a span{
background:transparent;
color:#000;
}
.x-tree-col {
float:left;
overflow:hidden;
padding:0 1px;
zoom:1;
}
.x-tree-col-text, .x-tree-hd-text {
overflow:hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
padding:3px 3px 3px 5px;
white-space: nowrap;
font:normal 11px arial, tahoma, helvetica, sans-serif;
}
.x-tree-headers {
background: #f9f9f9 url(../ext2/resources/images/default/grid/grid3-hrow.gif) repeat-x 0 bottom;
cursor:default;
zoom:1;
}
.x-tree-hd {
float:left;
overflow:hidden;
border-left:1px solid #eee;
border-right:1px solid #d0d0d0;
}
.task {
background-image:url(../shared/icons/fam/cog.png) !important;
}
.task-folder {
background-image:url(../shared/icons/fam/folder_go.png) !important;
}
Ext.tree.ColumnTree.js
/*
* Ext JS Library 2.2.1
* Copyright(c) 2006-2009, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
Ext.tree.ColumnTree = Ext.extend(Ext.tree.TreePanel, {
lines:false,
borderWidth: Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
cls:'x-column-tree',
onRender : function(){
Ext.tree.ColumnTree.superclass.onRender.apply(this, arguments);
this.headers = this.body.createChild(
{cls:'x-tree-headers'},this.innerCt.dom);
var cols = this.columns, c;
var totalWidth = 0;
for(var i = 0, len = cols.length; i < len; i++){
c = cols[i];
totalWidth += c.width;
this.headers.createChild({
cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
cn: {
cls:'x-tree-hd-text',
html: c.header
},
style:'width:'+(c.width-this.borderWidth)+'px;'
});
}
this.headers.createChild({cls:'x-clear'});
// prevent floats from wrapping when clipped
this.headers.setWidth(totalWidth);
this.innerCt.setWidth(totalWidth);
}
});
Ext.tree.ColumnNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
focus: Ext.emptyFn, // prevent odd scrolling behavior
renderElements : function(n, a, targetNode, bulkRender){
this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
var t = n.getOwnerTree();
var cols = t.columns;
var bw = t.borderWidth;
var c = cols[0];
var buf = [
'<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf ', a.cls,'">',
'<div class="x-tree-col" style="width:',c.width-bw,'px;">',
'<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
'<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow">',
'<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on">',
'<a hidefocus="on" class="x-tree-node-anchor" href="',a.href ? a.href : "#",'" tabIndex="1" ',
a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '>',
'<span unselectable="on">', n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</span></a>",
"</div>"];
for(var i = 1, len = cols.length; i < len; i++){
c = cols[i];
buf.push('<div class="x-tree-col ',(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
'<div class="x-tree-col-text">',(c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</div>",
"</div>");
}
buf.push(
'<div class="x-clear"></div></div>',
'<ul class="x-tree-node-ct" style="display:none;"></ul>',
"</li>");
if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
this.wrap = Ext.DomHelper.insertHtml("beforeBegin",
n.nextSibling.ui.getEl(), buf.join(""));
}else{
this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
}
this.elNode = this.wrap.childNodes[0];
this.ctNode = this.wrap.childNodes[1];
var cs = this.elNode.firstChild.childNodes;
this.indentNode = cs[0];
this.ecNode = cs[1];
this.iconNode = cs[2];
this.anchor = cs[3];
this.textNode = cs[3].firstChild;
}
});
~~~
2、 编写静态ColumnTree
~~~
/**
* @function column tree column tree 多列信息的tree
* @auhor: hoojo
* @createDate: Aug 29, 2010 10:39:02 PM
* @blog: blog.csdn.net/IBM_hoojo
* @email: hoojo_@126.com
*/
Ext.ns("Ext.hoo.tree");
Ext.hoo.tree.UserColumnTree = Ext.extend(Ext.tree.ColumnTree, {
constructor: function () {
Ext.hoo.tree.UserColumnTree.superclass.constructor.call(this, {
renderTo: "show",
title: "用户信息column tree",
width: 450,
hieght: 400,
autoScroll: true,
rootVisible: true,
columns: [{
header: "名称",
width: 100,
dataIndex: "name"
}, {
header: "性别",
width: 100,
dataIndex: "sex"
}, {
header: "年龄",
width: 100,
dataIndex: "age"
}, {
header: "班级",
width: 100,
dataIndex: "classes"
}],
loader: new Ext.tree.TreeLoader({
baseAttrs: {
uiProvider: Ext.tree.ColumnNodeUI
}
}),
root: new Ext.tree.AsyncTreeNode({
text: "用户基本信息",
children: [{
name: "大二一班",
classes: "二(1)班",
children: [{
name: "微微",
sex: "女",
age: 20,
classes: "二(1)班",
leaf: true
},{
name: "筱筱",
sex: "女",
age: 22,
classes: "二(1)班",
leaf: true
},{
name: "珠珠",
sex: "女",
age: 19,
classes: "二(1)班",
leaf: true
},{
name: "拉拉",
sex: "女",
age: 19,
classes: "二(1)班",
leaf: true
}]
},{
name: "二二班",
classes: "二(2)班",
children: [{
name: "放放",
sex: "男",
age: 22,
classes: "二(2)班",
leaf: true
},{
name: "枫枫",
sex: "男",
age: 22,
classes: "二(2)班",
leaf: true
}]
},{
name: "未成立",
sex: "",
age: 0,
classes: "二(3)班",
leaf: true
}]
})
});
this.on("click", this.onNodeClick, this);
},
onNodeClick: function (node, e) {
alert(Ext.encode(node.attributes) + "###" + node.leaf + "###" + Ext.encode(e.getPoint()) + "##" + e.getXY());
}
});
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "ext2/resources/images/default/s.gif";
new Ext.hoo.tree.UserColumnTree();
});
~~~
上面的就是一个静态的ColumnTree,在Ext的onReady函数中运行它。
3、 、需要在页面中导入ext库、css、即我们编写的js
~~~
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>TreePanel 示例</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta http-equiv="author" content="hoojo"/>
<meta http-equiv="email" content="hoojo_@126.com"/>
<meta http-equiv="ext-lib" content="version 2.2"/>
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>
<meta http-equiv="blog" content="http://hoojo.cnblogs.com"/>
<link rel="stylesheet" type="text/css" href="ext2/resources/css/ext-all.css" />
<link rel="stylesheet" type="text/css" href="jslib/column-tree.css" />
<script type="text/javascript" src="ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext2/ext-all.js"></script>
<script type="text/javascript" src="ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="jslib/Ext.tree.ColumnTree.js"></script>
<script type="text/javascript" src="jslib/Ext.hoo.tree.UserColumnTree.js"></script>
</head>
<body>
<div id="show" style="margin-left: 200px;"></div>
<div id="showBasic" style="margin-left: 200px; margin-top: 50px;"></div>
</body>
</html>
~~~
在浏览器中请求[http://localhost:8080/S2SMyBatis/columnTree.htm](http://localhost:8080/S2SMyBatis/columnTree.htm)
结果如下
[![clip_image004](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe1229379b5.gif "clip_image004")](http://hi.csdn.net/attachment/201105/11/0_1305107248dAkD.gif)
4、 下面编写远程数据的ColumnTree,代码如下:
~~~
Ext.ns("Ext.hoo.tree");
Ext.hoo.tree.UserBasicColumnTree = Ext.extend(Ext.tree.ColumnTree, {
constructor: function () {
Ext.hoo.tree.UserBasicColumnTree.superclass.constructor.call(this, {
renderTo: "showBasic",
title: "远程数据",
width: 550,
hieght: 400,
autoScroll: true,
rootVisible: true,
columns: [{
header: "编号",
width: 100,
dataIndex: "accountId"
}, {
header: "用户名称",
width: 100,
dataIndex: "username"
}, {
header: "密码",
width: 100,
dataIndex: "password"
}, {
header: "创建时间",
width: 150,
dataIndex: "createTime"
}],
loader: new Ext.tree.TreeLoader({
baseAttrs: {
uiProvider: Ext.tree.ColumnNodeUI
}
}),
root: new Ext.tree.AsyncTreeNode({
text: "用户基本信息",
children: []
}),
listeners: {
expandnode: {
fn: this.onExpandNode,
scope: this
}
}
});
},
onExpandNode: function (node) {
//只对未加载过的添加子结点,加载后不在重复加载;避免增加请求,浪费资源
if (!node.attributes.isLoad) {
Ext.Ajax.request({
url: Ext.hoo.tree.UserBasicColumnTree.TREE_DATA_URL,
success: function (response, options) {
node.attributes.isLoad = true;//设置加载标识
var nodes = Ext.decode(response.responseText); //将json的text转换成js对象
node.appendChild(nodes.results);
},
failure: function (response) {
Ext.Msg.alert("程序异常", response.responseText);
}
});
}
}
});
Ext.hoo.tree.UserBasicColumnTree.TREE_DATA_URL = "account!treeData.action";
~~~
由于服务器端返回来的数据是一个对象,而不是一个Array。所以客户端要将数据稍作处理,然后再添加到columnTree的children中。
5、 在上面的onReady中创建这个对象就可以了运行
~~~
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "ext2/resources/images/default/s.gif";
new Ext.hoo.tree.UserColumnTree();
new Ext.hoo.tree.UserBasicColumnTree();
});
~~~
同样在浏览器中请求[http://localhost:8080/S2SMyBatis/columnTree.htm](http://localhost:8080/S2SMyBatis/columnTree.htm)
可以看到
[![clip_image006](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122971731.gif "clip_image006")](http://hi.csdn.net/attachment/201105/11/0_1305107253F9qx.gif)
由于Account对象的数据形式不是一个完整的tree形态。所以展示效果就是上面的样子。正确的数据的格式的话,Account中至少包含以下属性:
Boolean leaf; List children; 这样就知道当前节点是否是叶子节点,并且知道其子元素。
Struts2、Spring3、MyBatis3整合ExtJS,完成ColumnTree 【一】
最后更新于:2022-04-01 12:01:19
开发环境:
System:Windows
WebBrowser:IE6+、Firefox3+
JavaEE Server:tomcat5.0.2.8、tomcat6
IDE:eclipse、MyEclipse 8
Database:MySQL
开发依赖库:
JavaEE5、Spring 3.0.5、Mybatis 3.0.4、myBatis-spring-1.0、Struts2.2.3、junit4.8.2、ext2.2.2
Email:hoojo_@126.com
Blog:[http://blog.csdn.net/IBM_hoojo](http://blog.csdn.net/IBM_hoojo)
[http://hoojo.cnblogs.com/](http://hoojo.cnblogs.com/)
上次介绍过Spring3、SpringMVC、MyBatis3整合,在线博文:[http://www.cnblogs.com/hoojo/archive/2011/04/15/2016324.html](http://www.cnblogs.com/hoojo/archive/2011/04/15/2016324.html)
###一、准备工作
1、 下载jar包
Struts2 jar下载:
[http://labs.renren.com/apache-mirror//struts/library/struts-2.2.3-lib.zip](http://labs.renren.com/apache-mirror/struts/library/struts-2.2.3-lib.zip)
Spring3 jar下载:
[http://ebr.springsource.com/repository/app/library/version/detail?name=org.springframework.spring&version=3.0.5.RELEASE](http://ebr.springsource.com/repository/app/library/version/detail?name=org.springframework.spring&version=3.0.5.RELEASE)
MyBatis3 jar 下载:[http://www.mybatis.org/java.html](http://www.mybatis.org/java.html)
2、 添加的jar包如下:
[![image](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe1228701fa.gif "image")](http://hi.csdn.net/attachment/201105/11/0_13051060949h9C.gif)
#### 二、Spring、MyBatis整合
1、 需要的jar文件如下:
[![clip_image002](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe12288ecc8.gif "clip_image002")](http://hi.csdn.net/attachment/201105/11/0_13051061019KQL.gif)
2、 在src目录中加入mybatis.xml,内容如下:
~~~
<xml version="1.0" encoding="UTF-8" ?>
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<-- 别名 -->
<typeAliases>
<typeAlias type="com.hoo.entity.Account" alias="account"/>
<typeAliases>
<configuration>
~~~
上面的配置文件中,可以加入一些公共、常用的MyBatis方面的全局配置。如handler、objectFactory、plugin、以及mappers的映射路径(由于在applicationContext-common中的SqlSessionFactoryBean有配置mapper的location,这里就不需要配置)等。这个类的文件名称和下面的applicationContext-common.xml中的configLocation中的值对应,不是随便写的。
3、 在src目录中添加applicationContext-common.xml中加入内容如下:
~~~
<xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">
<-- 配置DataSource数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://10.0.0.131:3306/ash2"/>
<property name="username" value="dev"/>
<property name="password" value="dev"/>
bean>
<-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis.xml"/>
<-- mapper和resultmap配置路径 -->
<property name="mapperLocations">
<list>
<-- 表示在com.hoo.resultmap包或以下所有目录中,以-resultmap.xml结尾所有文件 -->
<value>classpath:com/hoo/resultmap/**/*-resultmap.xmlvalue>
<value>classpath:com/hoo/entity/*-resultmap.xmlvalue>
<value>classpath:com/hoo/mapper/**/*-mapper.xmlvalue>
list>
property>
bean>
<-- 配置事务管理器,注意这里的dataSource和SqlSessionFactoryBean的dataSource要一致,不然事务就没有作用了 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
<-- 配置事务的传播特性 -->
<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIREDprop>
<prop key="edit*">PROPAGATION_REQUIREDprop>
<prop key="remove*">PROPAGATION_REQUIREDprop>
<prop key="insert*">PROPAGATION_REQUIREDprop>
<prop key="update*">PROPAGATION_REQUIREDprop>
<prop key="del*">PROPAGATION_REQUIREDprop>
<prop key="*">readOnlyprop>
props>
property>
bean>
<-- 通过扫描的模式,扫描目录在com/hoo/mapper目录下,所有的mapper都继承SqlMapper接口的接口, 这样一个bean就可以了 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.hoo.mapper"/>
<property name="markerInterface" value="com.hoo.mapper.SqlMapper"/>
<bean>
<beans>
~~~
DataSource,这里的是采用jdbc的dataSource;
SqlSessionFactory,是MyBatis团队提供整合Spring的SqlSession工厂Bean用它可以完成Spring和MyBatis的整合。SqlSessionFactoryBean需要注入DataSource,配置myBatis配置文件的location,以及配置mapper.xml和resultMap.xml文件的路径,可以用通配符模式配置。其实mapper里面是可以存放resultMap的内容的。由于resultMap文件的内容是和JavaBean及数据库表对象进行映射的。一般一张表、一个JavaBean(Model)对应一个resultMap文件。将resultMap独立出来提供可读性、维护性。
TransactionManager,事务管理器是采用jdbc的管理器。需要注入DataSource数据源,这里注入的数据源和SqlSessionFactory是同一个数据源。如果不同的数据源,事务将无法起到作用。
baseTransactionProxy,事务的传播特性才有spring提供的TransactionProxyFactoryBean这个事务代理工厂的拦截器类来完成。其他的暂时还没有可以支持事务配置的传播特性和隔离级别的方法,关于这里你可以参考:[http://www.cnblogs.com/hoojo/archive/2011/04/15/2017447.html](http://www.cnblogs.com/hoojo/archive/2011/04/15/2017447.html)
MapperScannerConfigurer是MyBatis的mapper接口的扫描器,通过这个配置可以完成对指定basePackage报下的类进行扫描,如果这些类有继承SqlMapper这个类的,将会是MyBatis的接口。不需要单独配置mapper,而完成注入。
4、 在src目录添加applicationContext-beans.xml这个文件,文件内容如下:
~~~
<xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<-- 注解探测器 -->
<context:component-scan base-package="com.hoo"/>
<beans>
~~~
这里面可以完成一下Action、Bean的注入配置
5、 JavaBean(Model、Entity)相关类、及resultMap.xml文件内容
Bean
~~~
package com.hoo.entity;
import java.io.Serializable;
import java.util.Date;
public class Account implements Serializable {
private static final long serialVersionUID = -7970848646314840509L;
private Integer accountId;
private String username;
private String password;
private Date createTime;
public Account() {
super();
}
//getter、setter
@Override
public String toString() {
return this.accountId + "#" + this.username + "#" + this.password + "#" + this.createTime;
}
}
account-resultMap.xml
xml version="1.0" encoding="UTF-8"?>
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="accountMap">
<resultMap type="com.hoo.entity.Account" id="accountResultMap">
<id property="accountId" column="account_id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="createTime" column="create_time"/>
<resultMap>
<mapper>
~~~
resultMap的type属性和对应的classpath对应,id会在mapper.xml文件中用到。下面的属性property是JavaBean的属性,column和数据库的字段对应。
6、 上面的applicationContext-common.xml中配置了SqlMapper,下面是SqlMapper代码,就一个空接口
~~~
package com.hoo.mapper;
/**
* function:所有的Mapper继承这个接口
* @author hoojo
* @createDate 2011-4-12 下午04:00:31
* @file SqlMapper.java
* @package com.hoo.mapper
* @project MyBatisForSpring
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public interface SqlMapper {
}
~~~
7、 定制我们自己的增删改查(CRUD)组件,接口如下
~~~
package com.hoo.mapper;
import java.util.List;
import org.springframework.dao.DataAccessException;
/**
* function: BaseSqlMapper继承SqlMapper,对Mapper进行接口封装,提供常用的增删改查组件;
* 也可以对该接口进行扩展和封装
* @author hoojo
* @createDate 2011-4-14 上午11:36:41
* @file BaseSqlMapper.java
* @package com.hoo.mapper
* @project MyBatisForSpring
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public interface BaseSqlMapper<T> extends SqlMapper {
public void add(T entity) throws DataAccessException;
public void edit(T entity) throws DataAccessException;
public void remvoe(T entity) throws DataAccessException;
public T get(T entity) throws DataAccessException;
public List<T> getList(T entity) throws DataAccessException;
}
~~~
当然实际开发中,增删改查组件一定不止这几个方法。这里只是随便挪列几个方法做一个示例。实际中可以根据需求进行添加方法,这里添加的方法可以用一个mapper.xml进行实现,然后注入这个mapper即可完成操作。也可以定义其他的mapper,如AccountMapper继承这个接口。然后为AccountMapper提供实现也是可以的。
8、 下面看看AccountMapper接口
~~~
package com.hoo.mapper;
import java.util.List;
import com.hoo.entity.Account;
/**
* function:继承SqlMapper,MyBatis数据操作接口;此接口无需实现类
* @author hoojo
* @createDate 2010-12-21 下午05:21:20
* @file AccountMapper.java
* @package com.hoo.mapper
* @project MyBatis
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public interface AccountMapper<T extends Account> extends BaseSqlMapper<T> {
public List<T> getAllAccount();
}
~~~
上面的AccountMapper继承了BaseSqlMapper,并且提供了自己所需要的方法。下面实现这个Mapper中和父接口的方法。
account-mapper.xml
~~~
<xml version="1.0" encoding="UTF-8"?>
<DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<-- namespace和定义的Mapper接口对应,并实现其中的方法 -->
<mapper namespace="com.hoo.mapper.AccountMapper">
<select id="getList" parameterType="com.hoo.entity.Account" resultType="list" resultMap="accountResultMap">
select * from account where username like '%' #{username} '%'
select>
<select id="getAllAccount" resultType="list" resultMap="accountResultMap">
select * from account
select>
<-- accountResultMap是account-resultmap.xml中定义的resultmap -->
<select id="get" parameterType="account" resultType="com.hoo.entity.Account" resultMap="accountResultMap">
[CDATA[
select * from account where account_id = #{accountId}
]]>
select>
<-- 自动生成id策略 -->
<insert id="add" useGeneratedKeys="true" keyProperty="account_id" parameterType="account">
insert into account(account_id, username, password)
values(#{accountId}, #{username}, #{password})
insert>
<update id="edit" parameterType="account">
update account set
username = #{username},
password = #{password}
where account_id = #{accountId}
update>
<delete id="remove" parameterType="account">
delete from account where account_id = #{accountId}
<delete>
<mapper>
~~~
mapper的namespace和接口的classpath对应,里面的sql语句的id和方法名称对应。这样就完成了AccountMapper的实现。
9、 下面来测试下AccountMapper的功能,代码如下:
~~~
package com.hoo.mapper;
import java.util.List;
import javax.inject.Inject;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit38.AbstractJUnit38SpringContextTests;
import com.hoo.entity.Account;
/**
* function: AccountMapper JUnit测试类
* @author hoojo
* @createDate 2011-4-12 下午04:21:50
* @file AccountMapperTest.java
* @package com.hoo.mapper
* @project MyBatisForSpring
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
@ContextConfiguration("classpath:applicationContext-*.xml")
public class AccountMapperTest extends AbstractJUnit38SpringContextTests {
@Inject
private AccountMapper<Account> mapper;
public void testGetAccount() {
Account acc = new Account();
acc.setAccountId(28);
System.out.println(mapper.get(acc));
}
public void testAdd() {
Account account = new Account();
account.setUsername("lisi@155.com");
account.setPassword("abc");
mapper.add(account);
}
public void testEditAccount() {
Account acc = new Account();
acc.setAccountId(28);
acc = mapper.get(acc);
System.out.println(acc);
acc.setUsername("Zhangsan22");
acc.setPassword("123123");
mapper.edit(acc);
System.out.println(mapper.get(acc));
}
public void testRemoveAccount() {
Account acc = new Account();
acc.setAccountId(28);
mapper.remvoe(acc);
System.out.println(mapper.get(acc));
}
public void testAccountList() {
List<Account> acc = mapper.getAllAccount();
System.out.println(acc.size());
System.out.println(acc);
}
public void testList() {
Account acc = new Account();
acc.setUsername("@qq.com");
List<Account> list = mapper.getList(acc);
System.out.println(list.size());
System.out.println(list);
}
}
~~~
运行上面的方法,没有错误基本上就算完成了Mapper的功能了。
10、 下面来写一个数据库操作的基类Dao,代码如下:
~~~
package com.hoo.dao;
import java.util.List;
import com.hoo.mapper.BaseSqlMapper;
/**
* function:
* @author hoojo
* @createDate 2011-4-14 上午11:30:09
* @file BaseMapperDao.java
* @package com.hoo.dao
* @project MyBatisForSpring
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public interface BaseMapperDao<T> {
@SuppressWarnings("unchecked")
public void setMapperClass(Class<? extends BaseSqlMapper> mapperClass);
public BaseSqlMapper<T> getMapper();
public boolean add(T entity) throws Exception;
public boolean edit(T entity) throws Exception;
public boolean remove(T entity) throws Exception;
public T get(T entity) throws Exception;
public List<T> getAll(T entity) throws Exception;
}
~~~
这个Dao定义了BaseSqlMapper中的方法,还提供了一个setMapperClass的方法。目的是在使用这个dao的时候,需要设置一个Mapper的class。且这个Mapper必须要是BaseSqlMapper或它的子类。所有的dao都可以用BaseMapperDao来完成CRUD操作即可,当BaseMapperDao的方法不够用的情况下,可以在接口中提供SqlSession、SqlSessionTemplate方法,让底层人员自己扩展所需要的方法。这里的dao和mapper好像有点冗余,因为dao和mapper完成的功能都是类似或是相同的。但是你可以在dao中,同时调用不同的mapper,来完成当前模块的dao所需要的功能。
11、 看看BaseMapperDao的实现代码
~~~
package com.hoo.dao.impl;
import java.util.List;
import javax.inject.Inject;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;
import com.hoo.dao.BaseMapperDao;
import com.hoo.mapper.BaseSqlMapper;
/**
* function:运用SqlSessionTemplate封装Dao常用增删改方法,可以进行扩展
* @author hoojo
* @createDate 2011-4-14 下午12:22:07
* @file BaseMapperDaoImpl.java
* @package com.hoo.dao.impl
* @project MyBatisForSpring
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
@SuppressWarnings("unchecked")
@Repository
public class BaseMapperDaoImpl<T> extends SqlSessionTemplate implements BaseMapperDao<T> {
@Inject
public BaseMapperDaoImpl(SqlSessionFactory sqlSessionFactory) {
super(sqlSessionFactory);
}
private Class<? extends BaseSqlMapper> mapperClass;
public void setMapperClass(Class<? extends BaseSqlMapper> mapperClass) {
this.mapperClass = mapperClass;
}
public BaseSqlMapper<T> getMapper() {
return this.getMapper(mapperClass);
}
public boolean add(T entity) throws Exception {
boolean flag = false;
try {
this.getMapper().add(entity);
flag = true;
} catch (Exception e) {
flag = false;
throw e;
}
return flag;
}
public boolean edit(T entity) throws Exception {
boolean flag = false;
try {
this.getMapper().edit(entity);
flag = true;
} catch (Exception e) {
flag = false;
throw e;
}
return flag;
}
public T get(T entity) throws Exception {
return this.getMapper().get(entity);
}
public List<T> getAll() throws Exception {
return this.getMapper().getList(null);
}
public boolean remove(T entity) throws Exception {
boolean flag = false;
try {
this.getMapper().remvoe(entity);
flag = true;
} catch (Exception e) {
flag = false;
throw e;
}
return flag;
}
}
~~~
这个实现类继承了SqlSessionTemplate,并且要注入SqlSessionFactory。提供的setMapperClass方法需要设置其BaseSqlMapper或它的子类。
好了,至此基本的CRUD的mapper和dao就算完成了。现在我们可以定义我们自己的业务模块,调用公共组件来完成增删改查操作。
12、 下面测试下这个BaseMapperDao功能
~~~
package com.hoo.dao;
import javax.inject.Inject;
import org.junit.Before;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit38.AbstractJUnit38SpringContextTests;
import com.hoo.entity.Account;
import com.hoo.mapper.AccountMapper;
/**
* function:
* @author hoojo
* @createDate 2011-4-14 下午01:08:49
* @file BaseMapperDaoImplTest.java
* @package com.hoo.dao
* @project MyBatisForSpring
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
@ContextConfiguration("classpath:applicationContext-*.xml")
public class BaseMapperDaoImplTest extends AbstractJUnit38SpringContextTests {
@Inject
private BaseMapperDao<Account> dao;
@Before
public void init() {
System.out.println(dao);
dao.setMapperClass(AccountMapper.class);
}
public void testGet() throws Exception {
init();
Account acc = new Account();
acc.setAccountId(28);
System.out.println(dao.get(acc));
}
public void testAdd() throws Exception {
init();
Account account = new Account();
account.setUsername("temp@156.com");
account.setPassword("abc");
System.out.println(dao.add(account));
}
}
~~~
13、 下面定义AccountDao接口
~~~
package com.hoo.dao;
import java.util.List;
import org.springframework.dao.DataAccessException;
/**
* function: Account数据库操作dao接口
* @author hoojo
* @createDate 2011-4-13 上午10:21:38
* @file AccountDao.java
* @package com.hoo.dao
* @project MyBatisForSpring
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public interface AccountDao<T> {
/**
* function: 添加Account对象信息
* @author hoojo
* @createDate 2011-4-13 上午11:50:05
* @param entity Account
* @return boolean 是否成功
* @throws DataAccessException
*/
public boolean addAccount(T entity) throws DataAccessException;
/**
* function: 根据id对到Account信息
* @author hoojo
* @createDate 2011-4-13 上午11:50:45
* @param id 编号id
* @return Account
* @throws DataAccessException
*/
public T getAccount(Integer id) throws DataAccessException;
/**
* function: 查询所有Account信息
* @author hoojo
* @createDate 2011-4-13 上午11:51:45
* @param id 编号id
* @return Account
* @throws DataAccessException
*/
public List<T> getList() throws DataAccessException;
}
~~~
14、 AccountDao实现类
~~~
package com.hoo.dao.impl;
import java.util.List;
import javax.inject.Inject;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;
import com.hoo.dao.AccountDao;
import com.hoo.dao.BaseMapperDao;
import com.hoo.entity.Account;
import com.hoo.mapper.AccountMapper;
/**
* function: Account数据库操作dao
* @author hoojo
* @createDate 2011-4-13 上午10:25:02
* @file AccountDaoImpl.java
* @package com.hoo.dao.impl
* @project MyBatisForSpring
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
@SuppressWarnings("unchecked")
@Repository
public class AccountDaoImpl<T extends Account> implements AccountDao<T> {
@Inject
private BaseMapperDao<Account> dao;
public boolean addAccount(T entity) throws DataAccessException {
dao.setMapperClass(AccountMapper.class);
boolean flag = false;
try {
dao.add(entity);
flag = true;
} catch (DataAccessException e) {
flag = false;
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
return flag;
}
public T getAccount(Integer id) throws DataAccessException {
dao.setMapperClass(AccountMapper.class);
Account acc = new Account();
T entity = null;
try {
acc.setAccountId(id);
entity = (T) dao.get(acc);
} catch (DataAccessException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
return entity;
}
public List<T> getList() throws DataAccessException {
dao.setMapperClass(AccountMapper.class);
List<T> list = null;
try {
list = (List<T>) ((AccountMapper)dao.getMapper()).getAllAcount();
} catch (DataAccessException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
return list;
}
}
~~~
注意,上面的方法都设置了MapperClass,表示当前dao的Mapper是AccountMapper对象。所有的mapper方法都是调用AccountMapper这个对象中的方法。
15、 下面定义服务器层接口
~~~
package com.hoo.biz;
import java.util.List;
import org.springframework.dao.DataAccessException;
/**
* function: biz层Account接口
* @author hoojo
* @createDate 2011-4-13 上午11:33:04
* @file AccountBiz.java
* @package com.hoo.biz
* @project MyBatisForSpring
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public interface AccountBiz<T> {
/**
* function: 添加Account对象信息
* @author hoojo
* @createDate 2011-4-13 上午11:50:05
* @param entity Account
* @return boolean 是否成功
* @throws DataAccessException
*/
public boolean addAccount(T entity) throws DataAccessException;
public boolean execute(T entity) throws DataAccessException;
/**
* function: 根据id对到Account信息
* @author hoojo
* @createDate 2011-4-13 上午11:50:45
* @param id 编号id
* @return Account
* @throws DataAccessException
*/
public T getAccount(Integer id) throws DataAccessException;
/**
* function: 查询所有Account信息
* @author hoojo
* @createDate 2011-4-13 上午11:51:45
* @param id 编号id
* @return Account
* @throws DataAccessException
*/
public List<T> getList() throws DataAccessException;
}
~~~
16、 AccountBiz的实现代码
~~~
package com.hoo.biz.impl;
import java.util.List;
import javax.inject.Inject;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import com.hoo.biz.AccountBiz;
import com.hoo.dao.AccountDao;
import com.hoo.entity.Account;
import com.hoo.exception.BizException;
/**
* function: Account Biz接口实现
* @author hoojo
* @createDate 2011-4-13 上午11:34:39
* @file AccountBizImpl.java
* @package com.hoo.biz.impl
* @project MyBatisForSpring
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
//@Component
@Service
public class AccountBizImpl<T extends Account> implements AccountBiz<T> {
@Inject
private AccountDao<T> dao;
public boolean addAccount(T entity) throws DataAccessException {
if (entity == null) {
throw new BizException(Account.class.getName() + "对象参数信息为Empty!");
}
return dao.addAccount(entity);
}
public T getAccount(Integer id) throws DataAccessException {
return dao.getAccount(id);
}
public List<T> getList() throws DataAccessException {
return dao.getList();
}
public boolean execute(T entity) throws DataAccessException {
if (entity == null) {
throw new BizException(Account.class.getName() + "对象参数信息为Empty!");
}
return dao.addAccount(entity);
}
}
~~~
直接注入AccountDao完成相关操作即可
17、 如果你需要在业务层设置事务传播特性,需要在applicationContext-bean.xml中加入配置如下:
~~~
<-- 为AccountBiz接口配置事务拦截器,baseTransactionProxy是事务拦截器,在Action中获取这个对象 -->
<bean id="accountBiz" parent="baseTransactionProxy">
<-- 设置target,也就是AccountBiz的实现类 -->
<property name="target" ref="accountBizImpl"/>
<bean>
~~~
这样在Action中注入accountBiz这个对象后,那么当这个对象出现DataAccessException异常的时候,就会自动回滚事务。
至此,Spring和MyBatis的整合就完成了。
ExtJS 文件浏览器,可以选择文件和文件夹
最后更新于:2022-04-01 12:01:17
话说long long ago,在本人开发项目时,需要导入一个文件夹(目录)下的文件,通过解析其中的数据并入库。
选择一个文件目录,好像没有这个控件。开始想到了不选目录,选文件。但是要选多个文件哦,而且数目不固定。
用file文件浏览不好,想到了用swfUpload可以选择多个文件。可以做到,但是还是选择文件不是选择目录。
不过我想要的,想呀想的……
诶~可以用ExtJS,自己扩展一个还是可以的。于是就有了今天这篇文章和这个文件浏览器。
extFileBrowser.html
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Ext 文件浏览选择器</title>
<meta http-equiv="author" content="hoojo">
<meta http-equiv="email" content="hoojo_@126.com">
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo">
<meta http-equiv="ext-lib" content="v2.2.1">
<meta http-equiv="version" content="v1.0">
<meta http-equiv="content-type" content="text/html; charset=gbk">
<link rel="stylesheet" type="text/css" href="ext-2.2/resources/css/ext-all.css" />
<script type="text/javascript" src="ext-2.2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext-2.2/ext-all.js"></script>
<script type="text/javascript" src="Ext.hoo.component.FileBrowserComponent.js"></script>
<script type="text/javascript">
Ext.onReady(function(){
Ext.BLANK_IMAGE_URL = "ext-2.2/resources/images/default/s.gif";
var fileBrowser = new Ext.hoo.component.FileBrowserWindow();
//var fileBrowser = new Ext.hoo.component.FileBrowserPanel();
fileBrowser.show();
fileBrowser.tree.getSelectionModel().on("beforeselect", function (sm, node) {
//只能选择文件夹,如果要选择文件修改这里即可
var flag = ((!node || (!!node && !!node.leaf)) || !(node.attributes.path.indexOf(":") != -1)) ? true : false;
fileBrowser.buttons[0].setDisabled(flag);
fileBrowser.buttons[1].setDisabled(flag);
}, fileBrowser.tree);
});
</script>
</head>
<body>
</body>
</html>
~~~
Ext.hoo.component.FileBrowserComponent.js
~~~
/**
* Ext.hoo.component.FileBrowserWindow 系统文件浏览选择组件,可以选定电脑上的文件或文件夹
* @author: hoojo
* @createDate 2010-10-17
* @email: hoojo_@126.com
* @blog: http://blog.csdn.net/IBM_hoojo
* @ext_lib: v2.2
* @version 1.0
*/
Ext.ns("Ext.hoo.component");
Ext.hoo.component.FileBrowserWindow = Ext.extend(Ext.Window, {
constructor: function (config) {
config = config || {};
Ext.apply(this, config);
this.tree = new Ext.hoo.tree.FileSystemTree();
Ext.hoo.component.FileBrowserWindow.superclass.constructor.call(this, {
renderTo: Ext.getBody(),
width: 300,
height: 300,
frame: true,
layout: "fit",
border: false,
title: "请选择",
items: this.tree,
buttons: [{
text: "新建",
disabled: true,
handler: this.onNewHandler,
scope: this
}, {
text: "确定",
disabled: true,
handler: this.onOkHandler,
scope: this
}, {
text: "取消",
handler: function () {
this.hide(Ext.getBody());
},
scope: this
}]
});
},
onNewHandler: function () {
this.setPath();
this.setFile();
Ext.Msg.prompt("新建文件", "请输入文件夹名称", this.onCreateDir, this);
},
onOkHandler: function () {
this.setPath();
this.setFile();
Ext.Msg.alert("路径", this.getPath());
},
onCreateDir: function (btn, text) {
if (btn == "ok") {
var path = this.getPath();
var node = this.getFile();
var dirName = text;
if (!!path && !!dirName) {
//本地添加模式
/*var newNode = new Ext.tree.AsyncTreeNode({
text: dirName,
path: node.attributes.path + "/" + dirName
});
node.expand(true, true);
node.appendChild(newNode);*/
//远程加载模式
Ext.Ajax.request({
url: Ext.hoo.tree.FileSystemTree.TREE_CREATE_DIR_URL,
params: {path: encodeURIComponent(path), dirName: encodeURIComponent(dirName)},//处理中文文件名,乱码问题
success: function (response, options) {
var returnNnode = Ext.decode(response.responseText);
node.appendChild(returnNnode);
node.expand(true);
},
failure: function (response) {
Ext.Msg.alert("程序异常", response.responseText);
}
});
}
}
},
setPath: function () {
this.path = this.tree.getSelectedNode().attributes.path || "";
},
setFile: function () {
this.nodeFile = this.tree.getSelectedNode() || {};
},
getPath: function () {
return this.path;
},
getFile: function () {
return this.nodeFile;
}
});
/**
* Ext.hoo.component.FileBrowserPanel 系统文件浏览选择组件,可以选定电脑上的文件或文件夹
* 不同于上面的是,这里是一个panel。有时候弹出window,并不能达到预想的效果。特别是window弹出在
* iframe中的Object对象上面,如:在播放器上面弹出此组件,拖动windwo的效果不理想。
* 这时就需要用模态,模态嵌入FileBrowserPanel组件即可
* @author: hoojo
* @createDate 2010-10-17
* @email: hoojo_@126.com
* @blog: http://blog.csdn.net/IBM_hoojo
* @ext_lib: v2.2
* @version 1.0
*/
Ext.hoo.component.FileBrowserPanel = Ext.extend(Ext.Panel, {
constructor: function (config) {
config = config || {};
Ext.apply(this, config);
this.tree = new Ext.hoo.tree.FileSystemTree();
Ext.hoo.component.FileBrowserPanel.superclass.constructor.call(this, {
renderTo: Ext.getBody(),
border: false,
width: 300,
height: 400,
layout: "fit",
title: "请选择",
items: this.tree,
buttons: [{
text: "新建",
disabled: true,
handler: this.onNewHandler,
scope: this
}, {
text: "确定",
disabled: true,
handler: function () {
this.path = this.tree.getSelectedNode().attributes.path || "";
this.nodeFile = this.tree.getSelectedNode() || {};
//window.returnValue = this.path;
//window.close();
Ext.Msg.alert("路径", this.path);
},
scope: this
}, {
text: "取消",
handler: function () {
this.hide(Ext.getBody());
//window.close();
},
scope: this
}]
});
},
onNewHandler: function () {
this.setPath();
this.setFile();
Ext.Msg.prompt("新建文件", "请输入文件夹名称", this.onCreateDir, this);
},
onCreateDir: function (btn, text) {
if (btn == "ok") {
var path = this.getPath();
var node = this.getFile();
var dirName = text;
if (!!path && !!dirName) {
//本地添加模式
/*var newNode = new Ext.tree.AsyncTreeNode({
text: dirName,
path: node.attributes.path + "/" + dirName
});
node.expand(true, true);
node.appendChild(newNode);*/
//远程加载模式
Ext.Ajax.request({
url: Ext.hoo.tree.FileSystemTree.TREE_CREATE_DIR_URL,
params: {path: encodeURIComponent(path), dirName: encodeURIComponent(dirName)},//处理中文文件名,乱码问题
success: function (response, options) {
var returnNnode = Ext.decode(response.responseText);
node.appendChild(returnNnode);
node.expand(true, true);
},
failure: function (response) {
Ext.Msg.alert("程序异常", response.responseText);
}
});
}
}
},
setPath: function () {
this.path = this.tree.getSelectedNode().attributes.path || "";
},
setFile: function () {
this.nodeFile = this.tree.getSelectedNode() || {};
},
getPath: function () {
return this.path;
},
getFile: function () {
return this.nodeFile;
}
});
/**
* Ext.hoo.tree.FileSystemTree 系统文件树,显示所有的文件
* @author: hoojo
* @createDate 2010-10-17
* @email: hoojo_@126.com
* @blog: http://blog.csdn.net/IBM_hoojo
* @ext_lib: v2.2
* @version 1.0
*/
Ext.ns("Ext.hoo.tree");
Ext.hoo.tree.FileSystemTree = Ext.extend(Ext.tree.TreePanel, {
constructor: function () {
Ext.hoo.tree.FileSystemTree.superclass.constructor.call(this, {
//rootVisible: false,
autoScroll: true,
root: new Ext.tree.AsyncTreeNode({
text: "My System Files",
id: "0",
path: "root",
children:[]
}),
listeners: {
expandnode: {
fn: this.onExpandNode,
scope: this
}
}
});
},
onExpandNode: function (node) {
//只对未加载过的添加子结点,加载后不在重复加载;避免增加请求,浪费资源
if (!node.attributes.isLoad) {
Ext.Ajax.request({
url: Ext.hoo.tree.FileSystemTree.TREE_DATA_URL,
params: {path: encodeURIComponent(node.attributes.path)},//处理中文文件名,乱码问题
success: function (response, options) {
node.attributes.isLoad = true;//设置加载标示
var nodes = Ext.decode(response.responseText);
node.appendChild(nodes);
},
failure: function (response) {
Ext.Msg.alert("程序异常", response.responseText);
}
});
}
},
getSelectedNode: function () {
return this.getSelectionModel().getSelectedNode();
}
});
Ext.hoo.tree.FileSystemTree.TREE_CREATE_DIR_URL = "http://localhost:8080/Test/FileBrowser?method=mkDir";
Ext.hoo.tree.FileSystemTree.TREE_DATA_URL = "http://localhost:8080/Test/FileBrowser?method=getData";
~~~
服务器端java code:
FileBrowser Servlet:
~~~
package com.hoo.servlet;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import net.sf.json.JSONArray;
import com.hoo.entity.FileInfo;
import com.hoo.util.FileUtils;
/**
* <b>function:</b> 查询本地硬盘文件数据、创建目录
* @project Test
* @package com.hoo.servlet
* @fileName FileBrowser.java
* @author hoojo
*/
public class FileBrowser extends HttpServlet {
private static final long serialVersionUID = 1599390137455995515L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String path = request.getParameter("path");
path = path == null ? "" : URLDecoder.decode(path, "UTF-8");
String method = request.getParameter("method");
FileInfo info = new FileInfo();
if ("getData".equals(method)) {
if ("root".equals(path)) {
FileSystemView fsv = FileSystemView.getFileSystemView();
File[] roots = fsv.getRoots(); //File.listRoots();
//桌面
for (File f : roots) {
info.getChildren().add(FileUtils.getFileInfo(f));
}
for (File f : roots[0].listFiles()) {
if (f.getName().contains("My Documents")) {
info.getChildren().add(FileUtils.getFileInfo(f));
}
}
FileInfo fileInfo = new FileInfo();
fileInfo.setName("我的电脑");
fileInfo.setPath("My Computer");
for (File fi : roots[0].listFiles()[0].listFiles()) {
fileInfo.getChildren().add(FileUtils.getFileInfo(fi));
}
info.getChildren().add(fileInfo);
fileInfo = new FileInfo();
fileInfo.setName("网上邻居");
fileInfo.setPath("Network Place");
for (File fi : roots[0].listFiles()[1].listFiles()) {
fileInfo.getChildren().add(FileUtils.getFileInfo(fi));
}
info.getChildren().add(fileInfo);
out.print(JSONArray.fromObject(info.getChildren()).toString());
} else if (path != null && !"".equals(path)) {
FileUtils.getFileInfo(info, new File(path), new String[] {"*"});
out.print(JSONArray.fromObject(info.getChildren()).toString());
}
}
if ("mkDir".equals(method)) {
String dirName = request.getParameter("dirName");
dirName = dirName == null ? "" : URLDecoder.decode(dirName, "UTF-8");
boolean success = false;
try {
success = FileUtils.mkDir(path, dirName);
FileInfo node = FileUtils.getFileInfo(new File(FileUtils.getDoPath(path) + dirName));
out.print(JSONArray.fromObject(node));
} catch (Exception e) {
e.printStackTrace();
success = false;
}
System.out.println(success);
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
这个类用到了json-lib.jar工具包,此包可以帮我们把java对象,包括list、map、array序列化成json的字符串。
至少用到以下依赖包:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe1228114e7.gif)
FileInfo 封装文件信息的java Bean:
~~~
package com.hoo.entity;
import java.util.ArrayList;
import java.util.List;
/**
* <b>function:</b>文件信息
* @author hoojo
* @createDate Oct 10, 2010 9:53:51 PM
* @file FileInfo.java
* @package com.hoo.entity
* @project MultiUpload
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class FileInfo {
//文件id
private String id;
//文件名称
private String name;
private String text;
//文件路径
private String path;
//是否有目录,有无子节点
private boolean leaf;
//修改日期
private String editDate;
//后缀
private String suffix;
//长度
private long length;
// 子目录中所有文件
private List<FileInfo> children = new ArrayList<FileInfo>();
//setter、getter
public String toString() {
return "name:" + name + ", size:" + children.size();
}
}
~~~
FileUtils 文件操作工具类
~~~
package com.hoo.util;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import com.hoo.entity.FileInfo;
/**
* <b>function:</b> 磁盘文件操作工具类
* @project Test
* @package com.hoo.util
* @fileName FileUtils.java
* @createDate 2010-10-4 下午03:32:42
* @author hoojo
*/
@SuppressWarnings("unused")
public abstract class FileUtils {
/**
* <b>function:</b>传递一个File,返回该文件的FileInfo实体类
* @author hoojo
* @createDate Oct 10, 2010 10:10:19 PM
* @param file File
* @return FileInfo
*/
public static FileInfo getFileInfo(File file) {
FileInfo info = new FileInfo();
if (file != null) {
info.setId(UUID.randomUUID().toString());
if (file.getName() == null || "".equals(file.getName()) || "::".equals(file.getName())) {
info.setName(file.getAbsolutePath());
} else {
info.setName(file.getName());
}
//info.setLeaf(file.isFile());
info.setLeaf(!file.isDirectory());
info.setLength(file.length());
info.setPath(getDoPath(file.getAbsolutePath()));
info.setSuffix(getType(file.getName()));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
date.setTime(file.lastModified());
info.setEditDate(sdf.format(date));
}
return info;
}
public static void setFileInfo(File file, FileInfo info) {
if (file != null && info != null) {
info.setId(UUID.randomUUID().toString());
if (file.getName() == null || "".equals(file.getName()) || "::".equals(file.getName())) {
info.setName(file.getAbsolutePath());
} else {
info.setName(file.getName());
}
//info.setLeaf(file.isFile());
info.setLeaf(!file.isDirectory());
info.setLength(file.length());
info.setPath(getDoPath(file.getAbsolutePath()));
info.setSuffix(getType(file.getName()));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
date.setTime(file.lastModified());
info.setEditDate(sdf.format(date));
}
}
/**
* <b>function:</b>处理后的系统文件路径
* @author hoojo
* @createDate Oct 10, 2010 12:49:31 AM
* @param path 文件路径
* @return 返回处理后的路径
*/
public static String getDoPath(String path) {
path = path.replace("//", "/");
String lastChar = path.substring(path.length() - 1);
if (!"/".equals(lastChar)) {
path += "/";
}
return path;
}
/**
* <b>function:</b>和文件后缀一样,不同的是没有“.”
* @author hoojo
* @createDate Oct 10, 2010 2:42:43 PM
* @param fileName 文件名称
* @return
*/
public static String getType(String fileName) {
int index = fileName.lastIndexOf(".");
if (index != -1) {
String suffix = fileName.substring(index + 1);//后缀
return suffix;
} else {
return null;
}
}
/**
* <b>function:</b> 得到指定目录下所有的文件集合
* @createDate 2010-10-20 下午02:20:06
* @author hoojo
* @param info 将数据设置在该变量中
* @param file 文件目录
*/
public static void getAllFileInfo(FileInfo info, File file) {
if (file.isDirectory()) {
long size = 0;
File[] allFiles = file.listFiles();
for (File f : allFiles) {
size += f.length();
FileInfo fi = getFileInfo(f);
info.getChildren().add(fi);
getAllFileInfo(fi, f);
}
info.setLength(size);
}
}
/**
* <b>function:</b> 得到当前目录所有文件
* @createDate 2010-10-20 下午02:21:06
* @author hoojo
* @param info 文件对象
* @param file 目录
*/
public static void getFileInfo(FileInfo info, File file, String[] allowTypes) {
if (file.isDirectory()) {
long size = 0;
File[] allFiles = file.listFiles();
for (File f : allFiles) {
size += f.length();
FileInfo fi = getFileInfo(f);
if (f.isDirectory()) {
info.getChildren().add(fi);
} else {
if (validTypeByName(f.getName(), allowTypes, true)) {
info.getChildren().add(fi);
}
}
}
info.setLength(size);
}
}
/**
* <b>function:</b> 根据文件名和类型数组验证文件类型是否合法,flag是否忽略大小写
* @author hoojo
* @createDate Oct 10, 2010 11:54:54 AM
* @param fileName 文件名
* @param allowTypes 类型数组
* @param flag 是否获得大小写
* @return 是否验证通过
*/
public static boolean validTypeByName(String fileName, String[] allowTypes, boolean flag) {
String suffix = getType(fileName);
boolean valid = false;
if (allowTypes.length > 0 && "*".equals(allowTypes[0])) {
valid = true;
} else {
for (String type : allowTypes) {
if (flag) {//不区分大小写后缀
if (suffix != null && suffix.equalsIgnoreCase(type)) {
valid = true;
break;
}
} else {//严格区分大小写
if (suffix != null && suffix.equals(type)) {
valid = true;
break;
}
}
}
}
return valid;
}
/**
* <b>function:</b> 在path目录下创建目录
* @createDate 2010-11-3 下午04:03:34
* @author hoojo
* @param path
* @param dirName
* @return
*/
public static boolean mkDir(String path, String dirName) {
boolean success = false;
File file = new File(getDoPath(path) + dirName);
if (!file.exists()) {
success = file.mkdirs();
}
return success;
}
}
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe1228362b7.gif)
点击新建可以创建新目录,确定可以获取选择的路径。
Ext 中,为Ext.form.HtmlEditor添加键盘事件
最后更新于:2022-04-01 12:01:15
这里扩展了Ext.form.HtmlEditor组件,为其添加了keyup,keydown,keypress事件监听。重写了Ext.form.HtmlEditor的方法:
initEditor、initComponent;
重写后的Ext.form.HtmlEditor示例:
~~~
/***
* 重写Ext.form.HtmlEditor,为其添加键盘事件
* author: hoojo
* email: hoojo_@126.com
* blog: http://blog.csdn.net/IBM_hoojo
* create by: 2010-8-14
* ext-lib: 3.2.1
* version: 1.0
*/
Ext.override(Ext.form.HtmlEditor, {
initEditor : function(){
var dbody = this.getEditorBody();
var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
ss['background-attachment'] = 'fixed'; // w3c
ss['background-color'] = 'white';
dbody.bgProperties = 'fixed'; // ie
Ext.DomHelper.applyStyles(dbody, ss);
if(this.doc){
try{
Ext.EventManager.removeAll(this.doc);
}catch(e){}
}
this.doc = this.getDoc();
Ext.EventManager.on(this.doc, {
'mousedown': this.onEditorEvent,
'dblclick': this.onEditorEvent,
'click': this.onEditorEvent,
'keyup': this.onEditorKeyUpEvent,
'keydown': this.onEditorKeyDownEvent,
'keypress': this.onEditorKeyPressEvent,
buffer:100,
scope: this
});
if(Ext.isGecko){
Ext.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
}
if(Ext.isIE || Ext.isSafari || Ext.isOpera){
Ext.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
}
this.initialized = true;
this.fireEvent('initialize', this);
this.doc.editorInitialized = true;
this.pushValue();
},
initComponent: function () {
this.addEvents(
'initialize',
'activate',
'beforesync',
'beforepush',
'sync',
'push',
'editmodechange',
'keydown',
'keyup',
'keypress'
);
},
onEditorKeyPressEvent : function(e){
this.updateToolbar();
this.fireEvent("keypress", this, e);
},
onEditorKeyUpEvent : function(e){
this.updateToolbar();
this.fireEvent("keyup", this, e);
},
onEditorKeyDownEvent : function(e){
this.updateToolbar();
this.fireEvent("keydown", this, e);
}
});
/**
* 重写后的Ext.form.HtmlEditor有了键盘的keyPress事件了
*/
Ext.ns("Ext.hoo.editor");
Ext.hoo.editor.HTMLEditor = Ext.extend(Ext.form.HtmlEditor, {
constructor: function () {
Ext.hoo.editor.HTMLEditor.superclass.constructor.call(this, {
renderTo: Ext.getBody(),
fieldLabel:'Biography',
height:200,
listeners: {
"keydown": function (editor, e) {
alert("keydown:" + editor.getValue());
},
"keyup": function (editor, e) {
alert("keyup:" + editor.getValue());
},
"keypress": function (editor, e) {
alert("keypress:" + editor.getValue());
}
}
});
}
});
~~~
注意:要添加键盘事件请添加Ext.override里的那段代码。这段是扩展代码,目的是为HtmlEditor添加键盘事件的。
html页面
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Ext 示例</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=gbk">
<link rel="stylesheet" type="text/css" href="ext-3.2.1/resources/css/ext-all.css" />
<script type="text/javascript" src="ext-3.2.1/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext-3.2.1/ext-all.js"></script>
<script type="text/javascript" src="HtmlEditor.js"></script>
<script type="text/javascript">
Ext.onReady(function(){
new Ext.hoo.editor.HTMLEditor();
});
</script>
</head>
<body>
</body>
</html>
~~~
ExtJS EditorGridPanel 示例之JSON格式Store前后台增删改查
最后更新于:2022-04-01 12:01:12
json格式传递数据示例,入口html页面:
~~~
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>用户数据编辑 用JsonReader 实现分页</title>
<meta http-equiv="Content-Type" content="text/html; charset=gbk" />
<meta http-equiv="author" content="hoojo">
<meta http-equiv="email" content="hoojo_@126.com">
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo">
<link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"></link>
<script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext2/ext-all.js"></script>
<script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="JsonPagingEditorGridPanel.js"></script>
<script type="text/javascript">
Ext.onReady(function (){
Ext.QuickTips.init();
//Ext.form.Field.prototype.msgTarget = "side";
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
new JsonPagingEditorGridPanel();
});
</script>
</head>
<body>
</body>
</html>``
~~~
JsonPagingEditorGridPanel.js:
~~~
/**
* 用JSON格式的数据形式:Ext.data.Store,Ext.data.JsonReader解析器,实现editorGrid的增删改查
* author: hoojo
* email: hoojo_@126.com
* blog: http://blog.csdn.net/IBM_hoojo
* ext-lib: v2.2
*/
/****************************************************************/
/*******JsonPagingEditorGridPanel*******/
/****************************************************************/
JsonPagingEditorGridPanel = Ext.extend(Ext.grid.EditorGridPanel, {
sexCombo: null,
inserted: [],
constructor: function () {
this.sexCombo = new Ext.form.ComboBox({
mode: "local",
value: "全部",
readOnly: true,
triggerAction: "all",
displayField: "sex",
//listAlign : "bl-tl", //下拉列表的显示方式 bl-tl是在上方显示,相反tl-bl是从下方显示
store: new Ext.data.SimpleStore({
data: ["男", "女", "全部"],
expandData: true,
fields: ["sex"]
}),
listeners: {
"select": {
fn: this.filterSex,
scope: this
}
}
});
this["store"] = new Ext.data.Store({
url: JsonPagingEditorGridPanel.USER_STORE_URL,
reader: new Ext.data.JsonReader({
id: "id", //维护当前数据的唯一性(和数据库主键类似,避免数据重复--过滤重复数据)
root: "users",
totalProperty: "totals"
},
Ext.data.Record.create(["id","name",
{name: "age", type: "int"}, "sex",
{name: "birthday", type: "date", dateFormat: "Y-m-d"}
])
),
sortInfo:{field:"id", direction:"ASC"} //排序
});
JsonPagingEditorGridPanel.superclass.constructor.call(this, {
renderTo: Ext.getBody(),
width: 480,
height: 300,
frame: true,
//loadMask:true, //显示加载旋转条
stripeRows: true, //隔行变色,区分表格行
clicksToEdit: 2, //表示点击多少次数才可以编辑表格
collapsible: true, //是否在右上角显示收缩按钮
animCollapse: true, //表示收缩(闭合)面板时,显示动画效果
trackMouseOver: true, //鼠标在行上移动时显示高亮
enableColumnMove: false,//禁止用户拖动表头
//disableSelection:true,
autoExpandColumn: "name", //这里指定的name的id ,此属性可以根据当前列 填充空白区域
title: "用户数据编辑器",
tbar: [
"->","查看方式:",
this.sexCombo,
{
text: "添加数据",
handler: this.onAddClick,
scope: this
},"-",{
text: "删除数据",
handler: this.onRemoveClick,
scope: this
},"-",{
text: "保存数据",
handler: this.onCommitStore,
scope: this
}
],
bbar: new Ext.PagingToolbar({
//width: 480, //如果pagingToolbar不在bbar[]括号中就不需要width,否则就要指定宽度才能显示displayInfo
pageSize: 5,
store: this.store,
displayInfo: true,
displayMsg: "显示第{0}-{1}条,共有{2}条记录",
emptyMsg: "没有记录"
}),
columns:[{
id: "name",
header: "姓名",
align: "center",
dataIndex: "name",
editor: new Ext.form.TextField({
allowBlank: false,
blankText: "姓名不能为空,必须输入"
})
},{
header: "年龄",
align: "center",
dataIndex: "age",
editor: new Ext.form.NumberField({
allowBlank: false,
allowNegative: false, //只能为正数
//maxValue: 1000000000,
grow: true, //前半部分显示正在改的数据,后半部分显示以前的老数据
selectOnFocus: true, //当获得焦点时,选中所有的文本内容
minValue: 1
})
},{
header: "性别",
align: "center",
dataIndex: "sex",
editor: new Ext.form.ComboBox({
mode: "local",
value: "男",
readOnly: true,
displayField: "sex",
triggerAction: "all",
store: new Ext.data.SimpleStore({
data: ["男", "女"],
expandData: true,
fields: ["sex"]
})
})
},{
header: "生日",
align: "center",
sortable: true,
dataIndex: "birthday",
renderer: Ext.util.Format.dateRenderer('Y-m-d'),
editor: new Ext.form.DateField({
format: "Y-m-d",
minValue: "1950-01-01",
disabledDays: [0, 7],//datefield的第0列:周日和第7列:周六不能编辑
disabledDaysText: "周末不能选择"
})
}],
sm: new Ext.grid.RowSelectionModel({
singleSelect: true
})
});
this.store.load({params: {start: 0, limit: 5}});
Ext.Ajax.on("requestcomplete", function (conn, response, options) {
//alert(response.responseText);
Ext.example.msg('Click','You clicked on "Action 1".');
});
},
filterSex: function (cob) {
if (cob.getValue() == "全部"){
this.store.clearFilter();
}
else
this.store.filter("sex", cob.value);
},
onAddClick: function () {
var rs = new Ext.data.Record({id: "",name: "", age: 1, sex: "", birthday: 0000-00-00});
this.getStore().add(rs);
rs.set("name", "ext");
rs.set("age", 22);
rs.set("sex", "男");
rs.set("birthday", new Date());
this.inserted.push(rs);
this.startEditing(this.store.getCount() - 1, 0);
},
saveInsertData: function (conn, response) {
var xml = response.responseXML;
var root = xml.documentElement;
for (var i = 0; i < root.childNodes.length; i++) {
this.inserted[i].set("id", root.childNodes[i].text);
}
this.getStore().commitChanges();
this.inserted = [];
},
onCommitStore: function () {
var mf = this.getStore().modified;
var temp = [];
for (var i = 0; i < mf.length; i ++) {
if (mf[i].get("id") == ""){
continue;
}
var data = {};
for (var j in mf[i].modified) {
data[j] = mf[i].get(j);
}
temp.push(Ext.apply(data, {id: mf[i].get("id")}));
}
for (var i = 0; i < this.inserted.length; i ++) {
temp.push(this.inserted[i].data);
}
Ext.Ajax.on("requestcomplete", function (conn, response, options) {
alert(response.responseText);
});
//Ext.Ajax.on("requestcomplete", this.saveInsertData, this);
//想服务器发送请求,传递修改的数据(只含修改的数据)
Ext.Ajax.request({url: "../ServiceServlet?method=edit", params: {content:Ext.util.JSON.encode(temp)}});
this.store.commitChanges();
this.filterSex(this.sexCombo);
},
onRemoveClick: function () {
var rs = this.getSelectionModel();
try{
if (rs.getCount() == 0) {
Ext.Msg.alert("系统提示", "没有选定数据,请选择数据行!");
}else {
Ext.Msg.confirm("系统提示", "您确定要删除当前数据吗?", this.removeUserInfo, this);
}
}catch(er) {
Ext.Msg.alert("系统提示", er.discription);
}
},
removeUserInfo: function (btnText) {
if (btnText == "yes"){
var rs = this.getSelectionModel().getSelected();
this.getStore().remove(rs);
if (rs.get("id") != "") {
Ext.Ajax.on("requestcomplete", function (conn, response, options) {
if (response.responseText == "success") {
alert("success");
}else {
alert("failure");
}
});
Ext.Ajax.request({url: "../ServiceServlet?method=remove", params: {id:rs.get("id")}});
}else {
this.inserted.remove(rs);
//this.getStore().modified.romove(rs);
}
}
}
});
JsonPagingEditorGridPanel.USER_STORE_URL = "http://localhost:8080/Demo3/ServiceServlet?method=json";
~~~
后台java code:
~~~
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.hoo.dao.IUser;
import com.hoo.dao.impl.UserDao;
import com.hoo.entity.UserInfo;
@SuppressWarnings({"unchecked", "serial"})
public class ServiceServlet extends HttpServlet {
private IUser dao = new UserDao();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("GBK");
PrintWriter out = response.getWriter();
StringBuilder builder = new StringBuilder();
String method = request.getParameter("method");
if ("json".equals(method)) {
int start = Integer.parseInt(request.getParameter("start"));
int limit = Integer.parseInt(request.getParameter("limit"));
Object[] obj = dao.loadUserInfo(start, limit);
List<UserInfo> list = (List<UserInfo>) obj[1];
builder.append("{totals:").append(obj[0]).append(",users:[");
for (int i = 0; i < list.size(); i++) {
UserInfo u = (UserInfo) list.get(i);
builder.append("{id:/"").append(u.getId())
.append("/",name:/"").append(u.getName())
.append("/",age:").append(u.getAge())
.append(",sex:/"").append(u.getSex())
.append("/",birthday:/"").append(u.getBirthday())
.append("/"}");
if (i < list.size()-1) {
builder.append(",");
}
}
builder.append("]}");
out.write(builder.toString());
}
if ("edit".equals(method)) {
String content = request.getParameter("content");
out.print(content);
}
if ("remove".equals(method)) {
Integer id = Integer.parseInt(request.getParameter("id"));
if (dao.removeUserInfo(id)) {
out.print("success");
}else {
out.print("failure");
}
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe1227c1d14.gif)
至此,ExtJS中常用的3中交互方式的示例全部在此。其中json格式交互方式最为常用。
原因是xml格式体积过于庞大,里面有标签过多。而array数组格式的文件,虽然提交很小。
传输速度快。但在数据量很大的情况下,数据的可读性几乎全无。后来出现了json,
它简化了xml文件提交庞大的问题,可读性也非常好、在网络中的传输速度也很快,且易于使用、学习。
ExtJS EditorGridPanel 示例之Array格式Store前后台增删改查(不支持分页)
最后更新于:2022-04-01 12:01:10
示例入口页面html:
~~~
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>用户数据编辑 User EditorGridPanel</title>
<meta http-equiv="Content-Type" content="text/html; charset=gbk" />
<meta http-equiv="author" content="hoojo">
<meta http-equiv="email" content="hoojo_@126.com">
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo">
<link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"></link>
<script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext2/ext-all.js"></script>
<script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="UserEditorGridPanel.js"></script>
<script type="text/javascript">
Ext.onReady(function (){
Ext.QuickTips.init();
//Ext.form.Field.prototype.msgTarget = "side";
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
new UserEditorGridPanel();
});
</script>
</head>
<body>
</body>
</html>
~~~
UserEditorGridPanel.js:
~~~
/**
* 用Array格式的数据形式:Ext.data.SimpleStore,默认数组解析器,实现editorGrid的增删改查
* 上一示例扩展了ArrayReader组件就支持分页,这里用默认的就不支持分页了;
* author: hoojo
* email: hoojo_@126.com
* blog: http://blog.csdn.net/IBM_hoojo
* ext-lib: v2.2
*/
/****************************************************************/
/*******UserEditorGridPanel*******/
/****************************************************************/
UserEditorGridPanel = Ext.extend(Ext.grid.EditorGridPanel, {
sexCombo: null,
inserted: [],
constructor: function () {
this.sexCombo = new Ext.form.ComboBox({
mode: "local",
value: "全部",
readOnly: true,
triggerAction: "all",
displayField: "sex",
//listAlign : "bl-tl", //下拉列表的显示方式 bl-tl是在上方显示,相反tl-bl是从下方显示
store: new Ext.data.SimpleStore({
data: ["男", "女", "全部"],
expandData: true,
fields: ["sex"]
}),
listeners: {
"select": {
fn: this.filterSex,
scope: this
}
}
});
this["store"] = new Ext.data.SimpleStore({
autoLoad: true,
url: UserEditorGridPanel.USER_STORE_URL,
fields: ["id","name",
"age", "sex",
{name: "birthday", type: "date", dateFormat: "Y-m-d"}
],
sortInfo:{field:"name", direction:"ASC"} //排序
});
UserEditorGridPanel.superclass.constructor.call(this, {
renderTo: Ext.getBody(),
width: 480,
height: 300,
frame: true,
stripeRows: true,
clicksToEdit: 2, //表示点击多少次数才可以编辑表格
collapsible: true, //是否在右上角显示收缩按钮
animCollapse: true, //表示收缩(闭合)面板时,显示动画效果
trackMouseOver: true, //鼠标在行上移动时显示高亮
enableColumnMove: false,//禁止用户拖动表头
autoExpandColumn: "name", //这里指定的name的id ,此属性可以根据当前列 填充空白区域
title: "用户数据编辑器",
tbar: [
"查看方式:",
this.sexCombo,
"-",
{
text: "保存数据",
handler: this.onCommitStore,
scope: this
}
],
bbar: [{
text: "添加数据",
handler: this.onAddClick,
scope: this
},"-",{
text: "删除数据",
handler: this.onRemoveClick,
scope: this
}],
columns:[{
id: "name",
header: "姓名",
align: "center",
dataIndex: "name",
editor: new Ext.form.TextField({
allowBlank: false,
blankText: "姓名不能为空,必须输入"
})
},{
header: "年龄",
align: "center",
dataIndex: "age",
editor: new Ext.form.NumberField({
allowBlank: false,
allowNegative: false, //只能为正数
//maxValue: 1000000000,
grow: true, //前半部分显示正在改的数据,后半部分显示以前的老数据
selectOnFocus: true, //当获得焦点时,选中所有的文本内容
minValue: 1
})
},{
header: "性别",
align: "center",
dataIndex: "sex",
editor: new Ext.form.ComboBox({
mode: "local",
value: "男",
readOnly: true,
displayField: "sex",
triggerAction: "all",
store: new Ext.data.SimpleStore({
data: ["男", "女"],
expandData: true,
fields: ["sex"]
})
})
},{
header: "生日",
align: "center",
sortable: true,
dataIndex: "birthday",
renderer: Ext.util.Format.dateRenderer('Y-m-d'),
editor: new Ext.form.DateField({
format: "Y-m-d",
minValue: "1950-01-01",
disabledDays: [0, 7],//datefield的第0列:周日和第7列:周六不能编辑
disabledDaysText: "周末不能选择"
})
}],
sm: new Ext.grid.RowSelectionModel({
singleSelect: true
})
});
/*Ext.Ajax.on("requestcomplete", function (conn, response, options) {
alert(response.responseText);
});*/
},
filterSex: function (cob) {
if (cob.getValue() == "全部"){
this.store.clearFilter();
}
else
this.store.filter("sex", cob.value);
},
onAddClick: function () {
var rs = new Ext.data.Record({id: "",name: "", age: 1, sex: "", birthday: 0000-00-00});
this.getStore().add(rs);
rs.set("name", "ext");
rs.set("age", 22);
rs.set("sex", "男");
rs.set("birthday", new Date());
this.inserted.push(rs);
this.startEditing(this.store.getCount() - 1, 0);
},
saveInsertData: function (conn, response) {
var xml = response.responseXML;
var root = xml.documentElement;
for (var i = 0; i < root.childNodes.length; i++) {
this.inserted[i].set("id", root.childNodes[i].text);
}
this.getStore().commitChanges();
this.inserted = [];
},
onCommitStore: function () {
var mf = this.getStore().modified;
var temp = [];
for (var i = 0; i < mf.length; i ++) {
if (mf[i].get("id") == ""){
continue;
}
var data = {};
for (var j in mf[i].modified) {
data[j] = mf[i].get(j);
}
temp.push(Ext.apply(data, {id: mf[i].get("id")}));
}
for (var i = 0; i < this.inserted.length; i ++) {
temp.push(this.inserted[i].data);
}
Ext.Ajax.on("requestcomplete", function (conn, response, options) {
alert(response.responseText);
});
//Ext.Ajax.on("requestcomplete", this.saveInsertData, this);
//想服务器发送请求,传递修改的数据(只含修改的数据)
Ext.Ajax.request({url: "../ServiceServlet?method=edit", params: {content:Ext.util.JSON.encode(temp)}});
this.store.commitChanges();
this.filterSex(this.sexCombo);
},
onRemoveClick: function () {
var rs = this.getSelectionModel();
try{
if (rs.getCount() == 0) {
Ext.Msg.alert("系统提示", "没有选定数据,请选择数据行!");
}else {
Ext.Msg.confirm("系统提示", "您确定要删除当前数据吗?", this.removeUserInfo, this);
}
}catch(er) {
Ext.Msg.alert("系统提示", er.discription);
}
},
removeUserInfo: function (btnText) {
if (btnText == "yes"){
var rs = this.getSelectionModel().getSelected();
this.getStore().remove(rs);
if (rs.get("id") != "") {
Ext.Ajax.on("requestcomplete", function (conn, response, options) {
if (response.responseText == "success") {
alert("success");
}else {
alert("failure");
}
});
Ext.Ajax.request({url: "../ServiceServlet?method=remove", params: {id:rs.get("id")}});
}else {
this.inserted.remove(rs);
//this.getStore().modified.romove(rs);
}
}
}
});
UserEditorGridPanel.USER_STORE_URL = "http://localhost:8080/Demo3/ServiceServlet?method=all";
~~~
后台增删改查方法Servlet 代码:
~~~
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.hoo.dao.IUser;
import com.hoo.dao.impl.UserDao;
import com.hoo.entity.UserInfo;
@SuppressWarnings({"unchecked", "serial"})
public class ServiceServlet extends HttpServlet {
private IUser dao = new UserDao();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("GBK");
PrintWriter out = response.getWriter();
StringBuilder builder = new StringBuilder();
String method = request.getParameter("method");
if ("all".equals(method)) {
List<UserInfo> list = dao.loadUserInfo();
builder.append("[");
for (int i = 0; i < list.size(); i++) {
UserInfo u = (UserInfo) list.get(i);
builder.append("[/"").append(u.getId())
.append("/",/"").append(u.getName())
.append("/",").append(u.getAge())
.append(",/"").append(u.getSex())
.append("/",/"").append(u.getBirthday())
.append("/"]");
if (i < list.size()-1) {
builder.append(",");
}
}
builder.append("]");
out.write(builder.toString());
}
if ("edit".equals(method)) {
String content = request.getParameter("content");
out.print(content);
}
if ("remove".equals(method)) {
Integer id = Integer.parseInt(request.getParameter("id"));
if (dao.removeUserInfo(id)) {
out.print("success");
}else {
out.print("failure");
}
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122772c70.gif)
插入图片以示真相,确实用默认的ArrayReader是不能分页。就算加上Ext.PagingToolbar分页工具条也是枉然,只是个摆设不能分页的,但可以结合静态数据分页的store还是可以的;见:[http://blog.csdn.net/IBM_hoojo/archive/2010/08/19/5823820.aspx](http://blog.csdn.net/IBM_hoojo/archive/2010/08/19/5823820.aspx)
ExtJS EditorGridPanel 示例之Array格式(自定义Array解析器)Store前后台增删改查
最后更新于:2022-04-01 12:01:08
本示例入口html页面:
~~~
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>用户数据编辑 用ArrayReader 实现分页</title>
<meta http-equiv="Content-Type" content="text/html; charset=gbk" />
<meta http-equiv="author" content="hoojo">
<meta http-equiv="email" content="hoojo_@126.com">
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo">
<link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"></link>
<script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext2/ext-all.js"></script>
<script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<!-- 用ArrayReader 实现分页,需要改进ArrayReader 的代码 -->
<script type="text/javascript" src="ArrayReader.js"></script>
<script type="text/javascript" src="ArrayPagingEditorGridPanel.js"></script>
<script type="text/javascript">
Ext.onReady(function (){
Ext.QuickTips.init();
//Ext.form.Field.prototype.msgTarget = "side";
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
new ArrayPagingEditorGridPanel();
});
</script>
</head>
<body>
</body>
</html>
~~~
ArrayPagingEditorGridPanel.js文件代码:
~~~
/**
* 用Array格式的数据形式:Ext.data.Store,自定义Ext.data.ArrayReader数组解析器,实现editorGrid的增删改查
* author: hoojo
* email: hoojo_@126.com
* blog: http://blog.csdn.net/IBM_hoojo
* ext-lib: v2.2
*/
/****************************************************************/
/*******ArrayPagingEditorGridPanel*******/
/****************************************************************/
ArrayPagingEditorGridPanel = Ext.extend(Ext.grid.EditorGridPanel, {
sexCombo: null,
inserted: [],
constructor: function () {
this.sexCombo = new Ext.form.ComboBox({
mode: "local",
value: "全部",
readOnly: true,
triggerAction: "all",
displayField: "sex",
//listAlign : "bl-tl", //下拉列表的显示方式 bl-tl是在上方显示,相反tl-bl是从下方显示
store: new Ext.data.SimpleStore({
data: ["男", "女", "全部"],
expandData: true,
fields: ["sex"]
}),
listeners: {
"select": {
fn: this.filterSex,
scope: this
}
}
});
this["store"] = new Ext.data.Store({
url: ArrayPagingEditorGridPanel.USER_STORE_URL,
reader: new Ext.data.ArrayReader({
id: "id", //维护当前数据的唯一性(和数据库主键类似,避免数据重复--过滤重复数据)
root: "users",
totalProperty: "totals"
},
Ext.data.Record.create(["id","name",
{name: "age", type: "int"}, "sex",
{name: "birthday", type: "date", dateFormat: "Y-m-d"}
])
),
sortInfo:{field:"name", direction:"ASC"} //排序
});
ArrayPagingEditorGridPanel.superclass.constructor.call(this, {
renderTo: Ext.getBody(),
width: 480,
height: 300,
frame: true,
stripeRows: true,
clicksToEdit: 2, //表示点击多少次数才可以编辑表格
collapsible: true, //是否在右上角显示收缩按钮
animCollapse: true, //表示收缩(闭合)面板时,显示动画效果
trackMouseOver: true, //鼠标在行上移动时显示高亮
enableColumnMove: false,//禁止用户拖动表头
autoExpandColumn: "name", //这里指定的name的id ,此属性可以根据当前列 填充空白区域
title: "用户数据编辑器",
tbar: [
"查看方式:",
this.sexCombo,
"-",
{
text: "保存数据",
handler: this.onCommitStore,
scope: this
}
],
bbar: [{
text: "添加数据",
handler: this.onAddClick,
scope: this
},"-",{
text: "删除数据",
handler: this.onRemoveClick,
scope: this
},new Ext.PagingToolbar({
pageSize: 5,
store: this.store
})],
columns:[{
id: "name",
header: "姓名",
align: "center",
dataIndex: "name",
editor: new Ext.form.TextField({
allowBlank: false,
blankText: "姓名不能为空,必须输入"
})
},{
header: "年龄",
align: "center",
dataIndex: "age",
editor: new Ext.form.NumberField({
allowBlank: false,
allowNegative: false, //只能为正数
//maxValue: 1000000000,
grow: true, //前半部分显示正在改的数据,后半部分显示以前的老数据
selectOnFocus: true, //当获得焦点时,选中所有的文本内容
minValue: 1
})
},{
header: "性别",
align: "center",
dataIndex: "sex",
editor: new Ext.form.ComboBox({
mode: "local",
value: "男",
readOnly: true,
displayField: "sex",
triggerAction: "all",
store: new Ext.data.SimpleStore({
data: ["男", "女"],
expandData: true,
fields: ["sex"]
})
})
},{
header: "生日",
align: "center",
sortable: true,
dataIndex: "birthday",
renderer: Ext.util.Format.dateRenderer('Y-m-d'),
editor: new Ext.form.DateField({
format: "Y-m-d",
minValue: "1950-01-01",
disabledDays: [0, 7],//datefield的第0列:周日和第7列:周六不能编辑
disabledDaysText: "周末不能选择"
})
}],
sm: new Ext.grid.RowSelectionModel({
singleSelect: true
})
});
this.store.load({params: {start: 0, limit: 5}});
/*Ext.Ajax.on("requestcomplete", function (conn, response, options) {
alert(response.responseText);
});*/
},
filterSex: function (cob) {
if (cob.getValue() == "全部"){
this.store.clearFilter();
}
else
this.store.filter("sex", cob.value);
},
onAddClick: function () {
var rs = new Ext.data.Record({id: "",name: "", age: 1, sex: "", birthday: 0000-00-00});
this.getStore().add(rs);
rs.set("name", "ext");
rs.set("age", 22);
rs.set("sex", "男");
rs.set("birthday", new Date());
this.inserted.push(rs);
this.startEditing(this.store.getCount() - 1, 0);
},
saveInsertData: function (conn, response) {
var xml = response.responseXML;
var root = xml.documentElement;
for (var i = 0; i < root.childNodes.length; i++) {
this.inserted[i].set("id", root.childNodes[i].text);
}
this.getStore().commitChanges();
this.inserted = [];
},
onCommitStore: function () {
var mf = this.getStore().modified;
var temp = [];
for (var i = 0; i < mf.length; i ++) {
if (mf[i].get("id") == ""){
continue;
}
var data = {};
for (var j in mf[i].modified) {
data[j] = mf[i].get(j);
}
temp.push(Ext.apply(data, {id: mf[i].get("id")}));
}
for (var i = 0; i < this.inserted.length; i ++) {
temp.push(this.inserted[i].data);
}
Ext.Ajax.on("requestcomplete", function (conn, response, options) {
alert(response.responseText);
});
//Ext.Ajax.on("requestcomplete", this.saveInsertData, this);
//想服务器发送请求,传递修改的数据(只含修改的数据)
Ext.Ajax.request({url: "../ServiceServlet?method=edit", params: {content:Ext.util.JSON.encode(temp)}});
this.store.commitChanges();
this.filterSex(this.sexCombo);
},
onRemoveClick: function () {
var rs = this.getSelectionModel();
try{
if (rs.getCount() == 0) {
Ext.Msg.alert("系统提示", "没有选定数据,请选择数据行!");
}else {
Ext.Msg.confirm("系统提示", "您确定要删除当前数据吗?", this.removeUserInfo, this);
}
}catch(er) {
Ext.Msg.alert("系统提示", er.discription);
}
},
removeUserInfo: function (btnText) {
if (btnText == "yes"){
var rs = this.getSelectionModel().getSelected();
this.getStore().remove(rs);
if (rs.get("id") != "") {
Ext.Ajax.on("requestcomplete", function (conn, response, options) {
if (response.responseText == "success") {
alert("success");
}else {
alert("failure");
}
});
Ext.Ajax.request({url: "../ServiceServlet?method=remove", params: {id:rs.get("id")}});
}else {
this.inserted.remove(rs);
//this.getStore().modified.romove(rs);
}
}
}
});
ArrayPagingEditorGridPanel.USER_STORE_URL = "http://localhost:8080/Demo3/ServiceServlet?method=arry";
~~~
后台java servlet交互代码:
~~~
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.hoo.dao.IUser;
import com.hoo.dao.impl.UserDao;
import com.hoo.entity.UserInfo;
@SuppressWarnings({"unchecked", "serial"})
public class ServiceServlet extends HttpServlet {
private IUser dao = new UserDao();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("GBK");
PrintWriter out = response.getWriter();
StringBuilder builder = new StringBuilder();
String method = request.getParameter("method");
if ("arry".equals(method)) {
int start = Integer.parseInt(request.getParameter("start"));
int limit = Integer.parseInt(request.getParameter("limit"));
Object[] obj = dao.loadUserInfo(start, limit);
List<UserInfo> list = (List<UserInfo>) obj[1];
builder.append("{totals:").append(obj[0]).append(",users:[");
for (int i = 0; i < list.size(); i++) {
UserInfo u = (UserInfo) list.get(i);
builder.append("[/"").append(u.getId())
.append("/",/"").append(u.getName())
.append("/",").append(u.getAge())
.append(",/"").append(u.getSex())
.append("/",/"").append(u.getBirthday())
.append("/"]");
if (i < list.size()-1) {
builder.append(",");
}
}
builder.append("]}");
out.write(builder.toString());
}
if ("edit".equals(method)) {
String content = request.getParameter("content");
out.print(content);
}
if ("remove".equals(method)) {
Integer id = Integer.parseInt(request.getParameter("id"));
if (dao.removeUserInfo(id)) {
out.print("success");
}else {
out.print("failure");
}
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
本示例用ArrayReader解析数组数据分页,需要扩展原有的ArrayReader.js文件,下面是扩展文件:
~~~
Ext.data.ArrayReader = Ext.extend(Ext.data.JsonReader, {
readRecords : function(o){
var sid = this.meta ? this.meta.id : null;
var recordType = this.recordType, fields = recordType.prototype.fields;
var records = [];
var root = this.meta ? this.meta["root"] ? o[this.meta["root"]] : o : o;
for(var i = 0; i < root.length; i++){
var n = root[i];
var values = {};
var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
for(var j = 0, jlen = fields.length; j < jlen; j++){
var f = fields.items[j];
var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
var v = n[k] !== undefined ? n[k] : f.defaultValue;
v = f.convert(v, n);
values[f.name] = v;
}
var record = new recordType(values, id);
record.json = n;
records[records.length] = record;
}
return {
records : records,
totalRecords : this.meta ? this.meta["totalProperty"] ? o[this.meta["totalProperty"]] : records.length : records.length
};
}
});
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122719c44.gif)
本示例最大的不同就是采用数据传递形式不同,用到的是Array格式。但ext v2.2版本中的ArrayReader结合Ext.data.Store
不支持分页,所以本示例进行扩展ArrayReader文件。
ExtJS EditorGridPanel 示例之xml格式Store前后台增删改查
最后更新于:2022-04-01 12:01:06
程序入口html页面:
~~~
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>用户数据编辑 XmlReader 实现分页</title>
<meta http-equiv="Content-Type" content="text/html; charset=gbk" />
<meta http-equiv="author" content="hoojo">
<meta http-equiv="email" content="hoojo_@126.com">
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo">
<link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"></link>
<script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext2/ext-all.js"></script>
<script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="UserPagingEditorGridPanel.js"></script>
<script type="text/javascript">
Ext.onReady(function (){
Ext.QuickTips.init();
//Ext.form.Field.prototype.msgTarget = "side";
Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
new UserPagingEditorGridPanel();
});
</script>
</head>
<body>
</body>
</html>
~~~
UserPagingEditorGridPanel.js:
~~~
/**
* 用xml格式的数据形式:Ext.data.Store、Ext.data.XmlReader解析器,实现editorGrid的增删改查
* author: hoojo
* email: hoojo_@126.com
* blog: http://blog.csdn.net/IBM_hoojo
* ext-lib: v2.2
*/
/****************************************************************/
/*******UserEditorGridPanel*******/
/****************************************************************/
UserPagingEditorGridPanel = Ext.extend(Ext.grid.EditorGridPanel, {
sexCombo: null,
inserted: [],
constructor: function () {
this.sexCombo = new Ext.form.ComboBox({
mode: "local",
value: "全部",
readOnly: true,
triggerAction: "all",
displayField: "sex",
//listAlign : "bl-tl", //下拉列表的显示方式 bl-tl是在上方显示,相反tl-bl是从下方显示
store: new Ext.data.SimpleStore({
data: ["男", "女", "全部"],
expandData: true,
fields: ["sex"]
}),
listeners: {
"select": {
fn: this.filterSex,
scope: this
}
}
});
this["store"] = new Ext.data.Store({
url: UserPagingEditorGridPanel.USER_STORE_URL,
reader: new Ext.data.XmlReader({
id: "id",
record: "user",
totalRecords: "totals" //如果是属性(非节点)要用@totals——<users totals="2">
},
Ext.data.Record.create(["id","name",
{name: "age", type: "int"}, "sex",
{name: "birthday", type: "date", dateFormat: "Y-m-d"}
])
),
sortInfo:{field:'name', direction:'ASC'} //排序
});
UserPagingEditorGridPanel.superclass.constructor.call(this, {
renderTo: Ext.getBody(),
width: 480,
height: 300,
frame: true,
stripeRows: true,
clicksToEdit: 1, //表示点击多少次数才可以编辑表格
collapsible: true, //是否在右上角显示收缩按钮
animCollapse: true, //表示收缩(闭合)面板时,显示动画效果
trackMouseOver: true, //鼠标在行上移动时显示高亮
enableColumnMove: false,//禁止用户拖动表头
autoExpandColumn: "name", //这里指定的name的id ,此属性可以根据当前列 填充空白区域
title: "用户数据编辑器",
tbar: [
"查看方式:",
this.sexCombo,
"-",
{
text: "保存数据",
handler: this.onCommitStore,
scope: this
},"-",{
text: "添加数据",
handler: this.onAddClick,
scope: this
},"-",{
text: "删除数据",
handler: this.onRemoveClick,
scope: this
}
],
bbar: new Ext.PagingToolbar({
pageSize: 5,
store: this.store
}),
columns:[{
id: "name",
header: "姓名",
align: "center",
dataIndex: "name",
editor: new Ext.form.TextField({
allowBlank: false,
blankText: "姓名不能为空,必须输入"
})
},{
header: "年龄",
align: "center",
dataIndex: "age",
editor: new Ext.form.NumberField({
allowBlank: false,
allowNegative: false, //只能为正数
maxValue: 200,
grow: true, //前半部分显示正在改的数据,后半部分显示以前的老数据
selectOnFocus: true, //当获得焦点时,选中所有的文本内容
minValue: 1
})
},{
header: "性别",
align: "center",
dataIndex: "sex",
editor: new Ext.form.ComboBox({
mode: "local",
value: "男",
readOnly: true,
displayField: "sex",
triggerAction: "all",
store: new Ext.data.SimpleStore({
data: ["男", "女"],
expandData: true,
fields: ["sex"]
})
})
},{
header: "生日",
align: "center",
sortable: true,
dataIndex: "birthday",
renderer: Ext.util.Format.dateRenderer('Y-m-d'),
editor: new Ext.form.DateField({
format: "Y-m-d",
minValue: "1950-01-01",
disabledDays: [0, 7],//datefield的第0列:周日和第7列:周六不能编辑
disabledDaysText: "周末不能选择"
})
}],
sm: new Ext.grid.RowSelectionModel({
singleSelect: true
})
});
this.store.load({params: {start: 0, limit: 5}});
//Ext.Ajax.on("requestcomplete", this.savaInsertData, this);
},
filterSex: function (cob) {
if (cob.getValue() == "全部"){
this.store.clearFilter();
}
else
this.store.filter("sex", cob.value);
},
onAddClick: function () {
var rs = new Ext.data.Record({id: "",name: "", age: 1, sex: "", birthday: 0000-00-00});
this.getStore().add(rs);
rs.set("name", "ext");
rs.set("age", 22);
rs.set("sex", "男");
rs.set("birthday", new Date());
this.inserted.push(rs);
this.startEditing(this.store.getCount() - 1, 0);
},
saveInsertData: function (conn, response) {
var xml = response.responseXML;
var root = xml.documentElement;
for (var i = 0; i < root.childNodes.length; i++) {
this.inserted[i].set("id", root.childNodes[i].text);
}
this.getStore().commitChanges();
this.inserted = [];
},
onCommitStore: function () {
var mf = this.getStore().modified;
var temp = [];
for (var i = 0; i < mf.length; i ++) {
if (mf[i].get("id") == ""){
continue;
}
var data = {};
for (var j in mf[i].modified) {
data[j] = mf[i].get(j);
}
temp.push(Ext.apply(data, {id: mf[i].get("id")}));
}
for (var i = 0; i < this.inserted.length; i ++) {
temp.push(this.inserted[i].data);
}
/*Ext.Ajax.on("requestcomplete", function (conn, response, options) {
alert(response.responseText);
});*/
//Ext.Ajax.on("requestcomplete", this.saveInsertData, this);
//想服务器发送请求,传递修改的数据(只含修改的数据)
Ext.Ajax.request({url: "../ServiceServlet?method=edit", params: {content:Ext.util.JSON.encode(temp)}});
this.store.commitChanges();
this.filterSex(this.sexCombo);
},
onRemoveClick: function () {
var rs = this.getSelectionModel();
try{
if (rs.getCount() == 0) {
Ext.Msg.alert("系统提示", "没有选定数据,请选择数据行!");
}else {
Ext.Msg.confirm("系统提示", "您确定要删除当前数据吗?", this.removeUserInfo, this);
}
}catch(er) {
Ext.Msg.alert("系统提示", er.discription);
}
},
removeUserInfo: function (btnText) {
if (btnText == "yes"){
var rs = this.getSelectionModel().getSelected();
this.getStore().remove(rs);
if (rs.get("id") != "") {
Ext.Ajax.on("requestcomplete", function (conn, response, options) {
if (response.responseText == "success") {
alert("success");
}else {
alert("failure");
}
});
Ext.Ajax.request({url: "../ServiceServlet?method=remove", params: {id:rs.get("id")}});
}else {
this.inserted.remove(rs);
this.getStore().modified.romove(rs);
}
}
}
});
UserPagingEditorGridPanel.USER_STORE_URL = "http://localhost:8080/Demo3/ServiceServlet?method=xml";
~~~
后台Servlet代码,ServiceServlet?method=xml方法代码
~~~
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.hoo.dao.IUser;
import com.hoo.dao.impl.UserDao;
import com.hoo.entity.UserInfo;
@SuppressWarnings({"unchecked", "serial"})
public class ServiceServlet extends HttpServlet {
private IUser dao = new UserDao();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("GBK");
response.setContentType("text/xml");//#text/xml# 一定要这样才能正常解析
PrintWriter out = response.getWriter();
StringBuilder builder = new StringBuilder();
String method = request.getParameter("method");
if ("xml".equals(method)) {
int start = Integer.parseInt(request.getParameter("start"));
int limit = Integer.parseInt(request.getParameter("limit"));
Object[] obj = dao.loadUserInfo(start, limit);
List<UserInfo> list = (List<UserInfo>) obj[1];
builder.append("<?xml version=/"1.0/" encoding=/"gbk/"?>")
//.append("<users totals=/"").append(obj[0]).append("/">");
.append("<users><totals>").append(obj[0]).append("</totals>");
for (int i = 0; i < list.size(); i++) {
UserInfo u = (UserInfo) list.get(i);
builder.append("<user><id>").append(u.getId())
.append("</id><name>").append(u.getName())
.append("</name><age>").append(u.getAge())
.append("</age><sex>").append(u.getSex())
.append("</sex><birthday>").append(u.getBirthday())
.append("</birthday></user>");
}
builder.append("</users>");
out.write(builder.toString());
}
if ("edit".equals(method)) {
String content = request.getParameter("content");
out.print(content);
}
if ("remove".equals(method)) {
Integer id = Integer.parseInt(request.getParameter("id"));
if (dao.removeUserInfo(id)) {
out.print("success");
}else {
out.print("failure");
}
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe122719c44.gif)
本示例用到的是Ext.data.Store/Ext.data.XmlReader解析器,解析后台传递的xml格式数据,当然也可以将UserPagingEditorGridPanel.USER_STORE_URL = "your.xml";这样也是可以的,但注意的是文件中定义的xml文档的格式要和store中的Ext.data.Record.create解析数据标签名称对应,本示例还用到了数据的简单过滤“性别”以及对脏数据的显示及其提交、修改等,下次将会提供更复杂的过滤查询。
ExtJS中grid按照使用Expand插件、分组显示、中文拼音首字母排序、改变行背景、列背景、静态数据分页综合案例
最后更新于:2022-04-01 12:01:03
~~~
/***
* grid基础综合案例
* 添加分页Ext.data.PagingMemoryProxy、重写Ext.data.Store支持中文汉字拼音字母首字母排序、
* Ext.data.GroupingStore分组(GroupingStore继承Store的)、
* 改变列背景色、行背景色、字体颜色getRowClass方法和renderer函数onRenderAgeCol的使用技巧
* 添加分组、行收缩展开插件Ext.grid.RowExpander使用及重写Ext.grid.RowExpander组件的
* 添加Ext.grid.GroupingView的groupTextTpl方法的使用
* author: hoojo
* create by: 2010-8-14
*/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>可分组显示、expand插件、中文排序的Grid/改变行背景/单元格背景/字体颜色/分页</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="content-Type" content="text/html; charset=utf-8">
<meta http-equiv="author" content="hoojo">
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo">
<link rel="stylesheet" type="text/css" href="ext2/resources/css/ext-all.css">
<style type="text/css">
.rowOdd {
background-color: #EFF7FF;
color: white;
}
.rowEven {
background-color: #CAE3FF;
color: white;
}
.cellBG {
background-color: #FFDD99;
font-weight: bold;
}
</style>
<script type="text/javascript" src="ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext2/ext-all.js"></script>
<script type="text/javascript" src="ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="jslib/PagingMemoryProxy.js"></script>
<!-- PagingMemoryProxy.js在ext-2.2/examples/locale可以找到 -->
<script type="text/javascript" src="jslib/RowExpander.js"></script>
<!-- RowExpander.jsext-2.2/examples/grid下可以找到-->
<script type="text/javascript" src="jslib/Ext.hoo.grid.ConformityGrid.js"></script>
</head>
<body>
</body>
</html>
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe1226aa801.gif)
look:按照国家分组的,其中还按照中文排序及Expand插件、分组修改单元格、行背景色、字体颜色
Ext.hoo.grid.ConformityGrid.js
~~~
/***
* grid基础综合案例
* 添加分页Ext.data.PagingMemoryProxy、重写Ext.data.Store支持中文汉字拼音字母首字母排序、
* Ext.data.GroupingStore分组(GroupingStore继承Store的)、
* 改变列背景色、行背景色、字体颜色getRowClass方法和renderer函数onRenderAgeCol的使用技巧
* 添加分组、行收缩展开插件Ext.grid.RowExpander使用及重写Ext.grid.RowExpander组件的
* 添加Ext.grid.GroupingView的groupTextTpl方法的使用
* author: hoojo
* create by: 2010-8-14
*/
Ext.ns("Ext.hoo.grid");
Ext.hoo.grid.ConformityGrid = Ext.extend(Ext.grid.GridPanel, {
//expander: null,
constructor: function () {
this.data = [
[1, "奥巴马", 48, "美国", "好像是美国总统"],
[3, "布朗", 20, "美国", "很常见的名字"],
[5, "次郎", 22, "日本", "据说是武大郎赐给的名称"],
[2, "多尔衮", 159, "中国", "差点历史就被改写"],
[4, "厄洛斯", 34, "英国", "不知哪里来的"],
[6, "弗莱德", 25, "美国", "和弗兰德很像"],
[8, "哥萨克", 24, "英国", "是萨克斯的弟弟么"],
[23, "汉德森", 48, "美国", "好像是部电影的主角"],
[13, "杰克", 20, "美国", "电影中常出现的配角名称"],
[15, "卡尔", 22, "美国", "是小时候看动画片的那个瘦猫,胖子是BC"],
[12, "露丝", 159, "英国", "很常见的名称"],
[14, "玛丽卡", 34, "美国", "这个名称好像不错哦"],
[16, "妮娜", 25, "美国", "在中国有叫‘妮’、‘娜’的,‘妮娜’不多见"],
[18, "欧德桑", 24, "英国", "Good Success!"]
],
this.store = new Ext.data.GroupingStore({
proxy: new Ext.data.PagingMemoryProxy(this.data),//后台分页只须将proxy改为url: "your url",
reader: new Ext.data.ArrayReader({}, [
{name: "id", type: "int", mapping: 0},
"name", "age", "country", "origin"
]),
sortInfo: {field: "name", direction: "asc"},
groupField: "country"
}),
this.expander = new Ext.grid.RowExpander({
tpl : new Ext.Template(
'<p><b>你是:</b> {name}</p><br>',
'<p><b>评价:</b> {origin}</p>'
)
}),
Ext.hoo.grid.ConformityGrid.superclass.constructor.call(this, {
renderTo: Ext.getBody(),
title: "可按中文排序的Grid/改变行背景/单元格背景/字体颜色",
height: 450,
width: 600,
frame: true,
autoScroll: true,
plugins: this.expander,
autoExpandColumn: "age",
columns: [this.expander, {
header: "编号",
dataIndex: "id",
sortable: true
}, {
header: "名称",
dataIndex: "name",
sortable: true
}, {
header: "年龄",
dataIndex: "age",
sortable: true,
renderer: this.onRenderAgeCol
}, {
header: "国家",
dataIndex: "country",
sortable: true
}],
sm: new Ext.grid.RowSelectionModel({singleSelect: true}),
bbar: new Ext.PagingToolbar({
store: this.store,
pageSize: 8,
displayInfo: true,
displayMsg: "显示{0}条到{1}条记录,总共{2}条记录",
emptyMsg: "没有数据记录"
}),
view: new Ext.grid.GroupingView({
forceFit:true,
autoFill: true,
groupTextTpl: '{text}({[values.rs.length]} {[values.rs.length > 1 ? "人" : "人"]})-记录[{startRow}]'/*,startRow是行索引
//如果不用Ext.grid.RowExpande插件,这里才有效果,在用插件的情况下改变行背景颜色需要覆盖插件中的getRowClass方法
getRowClass: function(record, index, rowParams, store) {
if (index % 2 == 0) {
return 'rowEven';
} else {
return 'rowOdd';
}
}*/
})
});
this.store.load({params: {start: 0, limit: 8}});
},
/**
* 列渲染器方法,在grid渲染的时候执行
* @param value 当前列的值
* @param metaData 当前列的css样式
* @param record 当前列的record记录
* @param rowIndex 行索引
* @param colIndex 当前列索引
* @param store 当前grid的store
*/
onRenderAgeCol: function (value, metaData, record, rowIndex, colIndex, store) {
if (rowIndex == 2) {//改变第四行的当前单元格背景颜色
metaData.attr = 'style="color: white; background-color: #A9C9E2;"';//添加style样式
} else if (value > 40) {
metaData.attr = 'style="color: red;"';
metaData.css = "cellBG";//添加class样式
}
if (rowIndex > 2) {
return "<a href='http://blog.csdn.net/IMB_hoojo' target='_blank'>【" + value + "】-【" + record.get("name") + "】-【" + store.getAt(0).data.name + "】</a>";
} else if (rowIndex == 1) {
metaData.cellAttr = "style='background-color: white; color: green;'";//不兼容firefox
return value;
} else {
return value;
}
}
});
/**
* 重写(覆盖)applySort方法
* 按照拼音字母进行排序
*/
Ext.override(Ext.data.Store, {
applySort: function () {
if (this.sortInfo && !this.remoteSort) {
var s = this.sortInfo;
var f = s.field;
var st = this.fields.get(f).sortType;
var fn = function (r1, r2) {
var v1 = st(r1.data[f]);
var v2 = st(r2.data[f]);
if (typeof(v1) == "string") {
return v1.localeCompare(v2);
}
return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
};
this.data.sort(s.direction, fn);
if (this.snapshot && this.snapshot != this.data) {
this.snapshot.sort(s.direction, fn);
}
}
}
});
/*
也可以下面这样写;
Ext.data.Store.prototype.applySort = function () {
};*/
Ext.override(Ext.grid.RowExpander, {
getRowClass: function(record, rowIndex, rowParams, store) {
rowParams.cols = rowParams.cols-1;
var content = this.bodyContent[record.id];
if(!content && !this.lazyRender){
content = this.getBodyContent(record, rowIndex);
}
if(content){
rowParams.body = content;
}
if (rowIndex % 2 == 0) {
return this.state[record.id] ? 'x-grid3-row-expanded rowEven' : 'x-grid3-row-collapsed rowEven';//添加样式rowEven
} else {
return this.state[record.id] ? 'x-grid3-row-expanded rowOdd' : 'x-grid3-row-collapsed rowOdd';//添加样式rowOdd
}
}
});
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "ext2/resources/images/default/s.gif";
var grid = new Ext.hoo.grid.ConformityGrid();
});
~~~
ExtJS中grid按照中文拼音首字母排序、改变行背景、列背景、静态数据分页不再困难
最后更新于:2022-04-01 12:01:01
本示例主要使用到了静态数据分页Ext.data.PagingMemoryProxy组件、Ext.PagingToolbar分页条、viewConfig的getRowClass方法、列column的renderer的方法使用、重写Ext.data.Store对中文排序的支持、以及Ext.Template结合grid的使用方法。
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>可按中文排序的Grid/改变行背景/单元格背景/字体颜色/静态数据分页</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="content-Type" content="text/html; charset=utf-8">
<meta http-equiv="author" content="hoojo">
<meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo">
<link rel="stylesheet" type="text/css" href="ext2/resources/css/ext-all.css">
<style type="text/css">
.rowOdd {
background-color: #EFF7FF;
color: white;
}
.rowEven {
background-color: #CAE3FF;
color: white;
}
.cellBG {
background-color: #FFDD99;
font-weight: bold;
}
</style>
<script type="text/javascript" src="ext2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="ext2/ext-all.js"></script>
<script type="text/javascript" src="ext2/build/locale/ext-lang-zh_CN-min.js"></script>
<script type="text/javascript" src="jslib/PagingMemoryProxy.js"></script>
<!-- PagingMemoryProxy.js在ext-2.2/examples/locale可以找到 -->
<script type="text/javascript" src="jslib/Ext.hoo.grid.SortChineseGridPanel.js"></script>
</head>
<body>
<div id="showGrid"></div>
<div id="showPanel"></div>
</body>
</html>
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-01_56fe121baec56.gif)
看图:改变行列背景、字体颜色、name按照中文拼音首字母排序:依次是a、b、c、c、e;及数据分页
Ext.hoo.grid.SortChineseGridPanel.js
~~~
/**
* 本示例主要使用到了静态数据分页Ext.data.PagingMemoryProxy组件、Ext.PagingToolbar分页条、
* viewConfig的getRowClass方法、列column的renderer的方法使用、重写Ext.data.Store对中文排序的支持、
* 以及Ext.Template结合grid的使用方法。
* author: hoojo
* createDate: 2010-8-14
**/
Ext.ns("Ext.hoo.grid");
Ext.hoo.grid.SortChineseGridPanel = Ext.extend(Ext.grid.GridPanel, {
constructor: function () {
this.data = [
[1, "奥巴马", 48],
[3, "布朗", 20],
[5, "次郎", 22],
[2, "多尔衮", 159],
[4, "厄洛斯", 34],
[6, "弗莱德", 25],
[8, "哥萨克", 24],
[23, "汉德森", 48],
[13, "杰克", 20],
[15, "卡尔", 22],
[12, "露丝", 159],
[14, "玛丽卡", 34],
[16, "妮娜", 25],
[18, "欧德桑", 24]
];
this.store = new Ext.data.Store({
proxy: new Ext.data.PagingMemoryProxy(this.data) ,
reader: new Ext.data.ArrayReader({}, [
{name: "id", type: "int", mapping: 0},
"name", "age"
]),
sortInfo: {field: "name", direction: "asc"}
});
Ext.hoo.grid.SortChineseGridPanel.superclass.constructor.call(this, {
renderTo: "showGrid",
title: "可按中文排序的Grid/改变行背景/单元格背景/字体颜色",
height: 300,
width: 600,
frame: true,
autoScroll: true,
autoExpandColumn: "age",
columns: [{
header: "编号",
dataIndex: "id",
sortable: true
}, {
header: "名称",
dataIndex: "name",
sortable: true
}, {
header: "年龄",
dataIndex: "age",
sortable: true,
renderer: this.onRenderAgeCol
}],
sm: new Ext.grid.RowSelectionModel({
singleSelect: true,
listeners: {
rowselect: {
fn: this.onRowSelected,
scope: this
}
}
}),
bbar: new Ext.PagingToolbar({
store: this.store,
pageSize: 5,
displayInfo: true,
displayMsg: "显示{0}条到{1}条记录,总共{2}条记录",
emptyMsg: "没有数据记录"
}),
viewConfig: {
forceFit: true,
autoFill: true,
getRowClass: function(record, index, rowParams, store) {
if (index % 2 == 0) {
return 'rowEven';
} else {
return 'rowOdd';
}
}
}
});
this.store.load({params: {start: 0, limit: 5}});
},
/**
* 列渲染器方法,在grid渲染的时候执行
* @param value 当前列的值
* @param metaData 当前列的css样式
* @param record 当前列的record记录
* @param rowIndex 行索引
* @param colIndex 当前列索引
* @param store 当前grid的store
*/
onRenderAgeCol: function (value, metaData, record, rowIndex, colIndex, store) {
if (rowIndex == 2) {//改变第四行的当前单元格背景颜色
metaData.attr = 'style="color: white; background-color: #A9C9E2;"';//添加style样式
} else if (value > 40) {
metaData.attr = 'style="color: red;"';
metaData.css = "cellBG";//添加class样式
}
if (rowIndex > 2) {
return "<a href='http://blog.csdn.net/IMB_hoojo' target='_blank'>【" + value + "】-【" + record.get("name") + "】-【" + store.getAt(0).data.name + "】</a>";
} else if (rowIndex == 1) {
metaData.cellAttr = "style='background-color: white; color: green;'";//不兼容firefox
return value;
} else {
return value;
}
},
onRowSelected: function (sm, rowIndex, record) {
var data = Ext.applyIf(record.data, {cls: this.getStyle()})
this.getViewTpl().overwrite(this.getViewPanel().body, data);
},
getStyle: function () {
return this.getViewPanel().getStyle();
},
setViewPanel: function (p) {
this.viewPanel = p || {};
},
getViewPanel: function () {
return this.viewPanel || {};
},
getViewTpl: function () {
return this.getViewPanel().getViewTpl();
}
});
/**
* 重写(覆盖)applySort方法
* 按照拼音字母进行排序
*/
Ext.override(Ext.data.Store, {
applySort: function () {
if (this.sortInfo && !this.remoteSort) {
var s = this.sortInfo;
var f = s.field;
var st = this.fields.get(f).sortType;
var fn = function (r1, r2) {
var v1 = st(r1.data[f]);
var v2 = st(r2.data[f]);
if (typeof(v1) == "string") {
return v1.localeCompare(v2);
}
return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
};
this.data.sort(s.direction, fn);
if (this.snapshot && this.snapshot != this.data) {
this.snapshot.sort(s.direction, fn);
}
}
}
});
/*
也可以下面这样写;
Ext.data.Store.prototype.applySort = function () {
};*/
Ext.ns("Ext.hoo.panel");
Ext.hoo.panel.ViewPanel = Ext.extend(Ext.Panel, {
constructor: function () {
this.viewTplMarkup = [
"编号:<span style='{cls}'>{id}</span><br/>",
"名称:<span style='{cls}'>{name}</span><br/>",
"年龄:<span style='{cls}'>{age}</span><br/>"
];
this.viewTpl = new Ext.Template(this.viewTplMarkup);
Ext.hoo.panel.ViewPanel.superclass.constructor.call(this, {
//title: "详细信息",
renderTo: "showPanel",
height: 100,
width: 600
});
},
getViewTpl: function () {
return this.viewTpl;
},
setStyle: function (cls) {
this.sty = cls || "color: red;";
},
getStyle: function () {
return this.sty || {};
}
});
Ext.onReady(function () {
Ext.BLANK_IMAGE_URL = "ext2/resources/images/default/s.gif";
var grid = new Ext.hoo.grid.SortChineseGridPanel();
var vp = new Ext.hoo.panel.ViewPanel();
vp.setStyle("color: red;")
grid.setViewPanel(vp);
});
~~~
ExtJS中,在FireFox浏览器中字体很小,解决方法
最后更新于:2022-04-01 12:00:59
ff-firefox中ext的中文文字会小一些,看上去很模糊。这个是由字体大小决定的。font-size: 11px;英文显示没有问题,在IE中也是可以的。但是中文就不能正常显示。所以将font-size: 12px;即可,但是要针对样式;下面是修改后的字体样式。导入即可!
~~~
@CHARSET "UTF-8";
.x-window-footer {
position: relative;
top: 0;
right: 0;
}
.x-tab-strip span.x-tab-strip-text {
font-size: 12px;
}
.x-panel-header {
font-size: 12px;
}
.x-tree-node {
font-size: 12px;
}
.x-grid3-hd-row td {
font-size: 12px;
}
.x-grid3-row td {
font-size: 12px;
line-height: 16px;
}
.x-tip .x-tip-bd {
font-size: 12px;
}
.x-tip h3 {
font-size: 12px;
}
.x-tip .x-tip-bd-inner {
font-size: 12px;
}
.x-panel-tl .x-panel-header {
font: normal 12px tahoma, arial, verdana, sans-serif;
}
.x-form-field {
font: 12px tahoma, arial, helvetica, sans-serif;
}
.x-small-editor .x-form-field {
font: 12px tahoma, arial, helvetica, sans-serif;
}
.x-combo-list-item {
font: 12px tahoma, arial, helvetica, sans-serif;
}
.x-menu-list-item {
font: 12px tahoma, arial, sans-serif;
}
.x-window-tl .x-window-header {
font: bold 12px tahoma, arial, verdana, sans-serif;
}
.ext-ie .x-form-text {
margin-top: 1px;
}
.x-form-item {
font: 12px tahoma, arial, helvetica, sans-serif;
}
.x-grid-group-hd div {
font: bold 12px tahoma, arial, helvetica, sans-serif;
}
.x-btn-text-icon .x-btn-center .x-btn-text {
background-position: 0pt 2px;
background-repeat: no-repeat;
padding: 3px 0pt 2px 18px;
}
.ext-gecko .x-btn button {
padding-left:0pt;
padding-right: 0pt;
}
.x-btn button {
font-size: 12px;
}
.x-toolbar td,.x-toolbar span,.x-toolbar input,.x-toolbar div,.x-toolbar select,.x-toolbar label {
font-size: 12px;
}
.x-tip .x-tip-body {
font-size: 12px;
}
~~~
eclipse MyEclipse中安装 spket插件 js文件内容字体变小解决方案
最后更新于:2022-04-01 12:00:57
在eclipse、MyEclipse中用Spket插件打开js文件后,发现字体非常小。(在每次重启eclipse时会出现)这个时候你只需要找到Window->General->Appearance->Colors and Fonts->Basic-Text Font,点击右边的change,随便修改字体大小调节下,然后再调回原来的大小,点击apply就可以了对应properties文件插件修改也是同样的方法
eclipse MyEclipse中安装 ext插件 spket提示
最后更新于:2022-04-01 12:00:54
### 安装插件
首先在网上找到spket的插件包,下载后解压可以看到有这样2个文件夹。分别是features、plugins,然后找到eclipse、MyEclipse的安装目录(C:/Program Files/MyEclipse),在这个文件夹中找到eclipse或是myeclipse文件夹,将features、plugins直接放入文件夹中即可。提示否覆盖选择是;
### 配置插件
首先找到window->Spket->JavaScript Profiles;
在右边的JavaScript Profiles中点击New,随便写个名称ext;
然后选择你刚才创建的ext,点击Add Library选择ExtJS即可;
展开菜单可以看到你选择的ExtJS,选中这项。
点击Add File,找到你的ExtJS库文件中的source目录(如果是v3的就是src)下面的ext.jsb文件。
注意:这里的src、source目录中一定要有extJS库的源码文件,不能删除。而且ext.jsb要在这个文件夹下才可以。如果src、source没有源码文件或ext.jsb,而是让ext.jsb单独放在其他文件夹下是不能提示的。
最后展开可以看到你选择的jsb文件下有好多组件,选择你要使用的组件。只有选择的组件才有提示,不选择的就没有提示了。
完后还需要选择你新建的ext,点击右边的Default,设置为默认;
最后重启你的eclipse或MyEclipse即可;
插件虽好,不要过于依赖。在开发中可以使用提高开发效率,平时学习建议用NotePad、EditPlus等无提示软件、IDE即可。当然还有Spket的可视化拖拉的IDE,感觉不怎么成熟,不建议使用;
ExtJS 中用js 操作cookie的方法
最后更新于:2022-04-01 12:00:52
cookie.js文件
~~~
偶尔发现ExtJS中有操作cookie的js方法,拿来给大家分享下。
var Cookies = {};
Cookies.set = function(name, value){
var argv = arguments;
var argc = arguments.length;
var expires = (argc > 2) ? argv[2] : null;
var path = (argc > 3) ? argv[3] : '/';
var domain = (argc > 4) ? argv[4] : null;
var secure = (argc > 5) ? argv[5] : false;
document.cookie = name + "=" + escape (value) +
((expires == null) ? "" : ("; expires=" + expires.toGMTString())) +
((path == null) ? "" : ("; path=" + path)) +
((domain == null) ? "" : ("; domain=" + domain)) +
((secure == true) ? "; secure" : "");
};
Cookies.get = function(name){
var arg = name + "=";
var alen = arg.length;
var clen = document.cookie.length;
var i = 0;
var j = 0;
while(i < clen){
j = i + alen;
if (document.cookie.substring(i, j) == arg)
return Cookies.getCookieVal(j);
i = document.cookie.indexOf(" ", i) + 1;
if(i == 0)
break;
}
return null;
};
Cookies.clear = function(name) {
if(Cookies.get(name)){
document.cookie = name + "=" +
"; expires=Thu, 01-Jan-70 00:00:01 GMT";
}
};
Cookies.getCookieVal = function(offset){
var endstr = document.cookie.indexOf(";", offset);
if(endstr == -1){
endstr = document.cookie.length;
}
return unescape(document.cookie.substring(offset, endstr));
};
~~~
示例:
~~~
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>OperateCookie.html</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="cookie.js"></script>
<script type="text/javascript">
function set() {
Cookies.set("name", "tom");
Cookies.set("sex", "男");
}
function get() {
alert(Cookies.get("name"));
alert(Cookies.get("sex"));
}
function clear(s) {
Cookies.clear(s);
}
</script>
</head>
<body>
<input type="button" value=" set " onclick="set()"/>
<input type="button" value=" get " onclick="get()"/>
<input type="button" value=" clear sex " onclick="clear('sex')"/>
<input type="button" value=" clear name " onclick="clear('name')"/>
</body>
</html>
~~~
可以参考:[http://blog.csdn.net/IBM_hoojo/archive/2010/07/02/5709282.aspx](http://blog.csdn.net/IBM_hoojo/archive/2010/07/02/5709282.aspx)
前言
最后更新于:2022-04-01 12:00:50
> 原文出处:[ExtJS 专栏](http://blog.csdn.net/column/details/extjs-by-hoojo.html)
作者:[ibm_hoojo](http://blog.csdn.net/ibm_hoojo)
**本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!**
# ExtJS 专栏
> 介绍ExtJS相关知识、技术文章