问题
Hy there,
i need the ability to change the background-color for the different states (normal, hover, pressed) of a button dynamically.
What i've came up with so far is the following: http://jsfiddle.net/suamikim/c3eHh/
Ext.onReady(function() {
function updateBackground() {
var theWin = win || this, // neccessary because of the call from the afterrender-event
btn = theWin.down('#btnTest'),
bckgr = theWin.down('#btnBckgr').getValue(),
bckgrHover = theWin.down('#btnBckgrHover').getValue(),
bckgrPressed = theWin.down('#btnBckgrPressed').getValue();
// Set normal background as button-style
// Should be ok
$('#' + btn.id).css('background', bckgr);
// Toggle background when hover-state changes
// Are there any downsides if this function gets called everytime the updateBackground-method is called? Do i have to dispose anything before binding the functions again?
$('#' + btn.id).hover(function() {
$('#' + btn.id).css('background', bckgrHover);
}, function() {
$('#' + btn.id).css('background', bckgr);
}
);
// Set the background for pressed button as document style
// Problems:
// - Pollutes the document-header if called multiple times...
// - Background does not change anymore on hover for pressed button because of the !important, but without important it wouldn't show the pressed background at all...
$('<style type="text/css"> #' + btn.id + '.x-btn-pressed { background: ' + bckgrPressed + ' !important } </style>').appendTo('head');
};
// Create a window with the propertygrid
var win = Ext.create('Ext.window.Window', {
width: 800,
height: 200,
layout: 'fit',
tbar: {
defaultType: 'textfield',
defaults: {
listeners: {
blur: updateBackground
}
},
items: [
'Background (CSS):', { itemId: 'btnBckgr', value: '#77ABD8' },
'Background hover (CSS):', { itemId: 'btnBckgrHover', value: '#CC1C1C' },
'Background pressed (CSS):', { itemId: 'btnBckgrPressed', value: '#7D4FC6' }
]
},
items: [{
xtype: 'button',
itemId: 'btnTest',
text: 'test button',
enableToggle: true
}],
listeners: {
'afterrender': updateBackground
}
}).show();
});
This works basically but there are some questions left to me:
1)
Is it ok to call the hover-function of jquery everytime the updateBackground-method is called?
According to the jquery-doc (http://api.jquery.com/hover/) this functions binds the 2 given functions to the mouse-enter- & mouse-leave-events of the given element.
Does this mean that it binds new functions everytime i call it or does it update the already bound ones or does it dispose the already bound ones automatically before binding the new ones...
In short: do i have to dispose anything before binding the new functions with $.hover?
2)
I set the style for the pressed state as document-style which means that the document-header gets polluted if the updateBackground-function is called often (everytime one of the text-fields fires the blur-event in my test-case).
Is there any better way to achieve the same goal or can i remove the already set styles before adding new ones?
3)
The background for hover-state doesn't appear if the button is pressed because of the !important-flag in the pressed-style. I can't just remove this flag because the background of the pressed-state wouldn't show correctely without it...
Any solutions?
In general i'd be open for every suggestion on how to solve this problem in a completely different way.
Thanks,
mik
Edit:
The code above is just an example. Actually i need to be able to change the background-attribute for other ext-controls than buttons too (panels, checkboxes, ...) but i think that i can adopt a working solution for buttons to those other controls myself.
Please keep this in mind and don't specify the answer too much on buttons. It should be as generic as possible...
回答1:
Using some more specific css selectors you can take advantage of Ext's pressedCls and overCls configs. http://docs.sencha.com/ext-js/4-1/#!/api/Ext.button.Button-cfg-pressedCls http://docs.sencha.com/ext-js/4-1/source/Button2.html#Ext-button-Button-cfg-overCls
.x-btn.my-over {
background: blue;
}
/*Ext is not consistent */
.x-btn.x-btn-my-pressed {
background: red;
}
new Ext.button.Button({
overCls : 'my-over',
pressedCls : 'my-pressed',
//needs to be true to have the pressed cls show
enableToggle : true,
text : 'My button',
renderTo : Ext.getBody(),
})
Edit for a more dynamic, generic solution
Ext.define('DynamicStyleState', {
alias : 'plugin.dynamicStyleState',
extend : Ext.AbstractPlugin,
/**
* @cfg
*/
elementProperty : 'el',
/**
* @property
*/
pressed : false,
init : function(component) {
this.component = component;
this.component.on('afterrender', this._onAfterrender, this);
},
/**
* @protected
*/
clearStyle : function() {
this.el.setStyle({
background : ''
});
},
/**
* @protected
* meant to be overriden
*/
getHoverStyle : function() {
return {
background : 'blue'
};
},
/**
* @protected
* meant to be overriden
*/
getPressedStyle : function() {
return {
background : 'red'
};
},
_onAfterrender : function() {
this.el = this.component[this.elementProperty];
this.el.hover(this._onElementMouseIn, this._onElementMouseOut, this);
this.el.on('click', this._onElementClick, this);
},
_onElementMouseIn : function() {
if(!this.pressed) {
this.el.setStyle(this.getHoverStyle());
}
},
_onElementMouseOut : function() {
if(!this.pressed) {
this.clearStyle();
}
},
_onElementClick : function(e) {
this.pressed = !this.pressed;
if(this.pressed) {
this.el.setStyle(this.getPressedStyle());
} else {
//mimic mouse in
if(e.within(this.el)) {
this.el.setStyle(this.getHoverStyle());
}
}
}
});
Since you want something that works on more than just button this should work on any component.
Here is an example usage:
var headerHoverColor = new Ext.form.field.Text({
fieldLabel : 'Header hover color',
value : 'orange',
renderTo : Ext.getBody()
});
var headerPressedColor = new Ext.form.field.Text({
fieldLabel : 'Header pressed color',
value : 'black',
renderTo : Ext.getBody()
})
new Ext.panel.Panel({
plugins : {
ptype : 'dynamicStyleState',
elementProperty : 'body'
},
header : {
plugins : {
ptype : 'dynamicStyleState',
getHoverStyle : function() {
return {
background : headerHoverColor.getValue()
}
},
getPressedStyle : function() {
return {
background : headerPressedColor.getValue()
}
}
}
},
height : 300,
width : 300,
renderTo : Ext.getBody(),
title : 'Panel'
});
回答2:
Ok, i just found a solution which should cover all the problems described above:
I add both, the pressed
and hovered
style directly to the header.
To make sure that the header won't be polluted i just remove the style-elements dynamically with jQuery
's detach-function from the header before appending new ones.
Working example
And the code for the dynamic changing of the background:
function updateBackground() {
var theWin = win || this, // neccessary because of the call from the afterrender-event
btn = theWin.down('#btnTest'),
bckgr = theWin.down('#btnBckgr').getValue(),
bckgrHover = theWin.down('#btnBckgrHover').getValue(),
bckgrPressed = theWin.down('#btnBckgrPressed').getValue();
// Set normal background as button-style
// Should be ok
$('#' + btn.id).css('background', bckgr);
// Set the background for hovered and pressed button as document style
// Remove style-element if it already exists to not pollute the document-head
$('head style:contains("' + btn.id + ':hover")').detach();
$('<style type="text/css"> #' + btn.id + ':hover { background: ' + bckgrHover + ' !important } </style>').appendTo('head');
$('head style:contains("' + btn.id + '.x-btn-pressed")').detach();
$('<style type="text/css"> .x-body #' + btn.id + '.x-btn-pressed { background: ' + bckgrPressed + ' !important } </style>').appendTo('head');
};
Seems to work for me but I'm still open for any suggestions/improvements to this!
Thanks.
来源:https://stackoverflow.com/questions/12106952/how-to-change-background-of-hovered-and-pressed-extjs-button-dynamically