如何动态更改hover和按下的extjs按钮的背景

那里,

我需要能够动态地改变按钮的不同状态(正常,hover,按下)的背景颜色。

到目前为止我想出的是以下内容: 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... $(' #' + btn.id + '.x-btn-pressed { background: ' + bckgrPressed + ' !important } ').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(); }); 

这基本上有效,但还有一些问题留给我:

1)

每次调用updateBackground-method时都可以调用jquery的hover-function吗?

根据jquery-doc( http://api.jquery.com/hover/ ),这个函数将给定的两个函数绑定到给定元素的mouse-enter-和mouse-leave-events。

这是否意味着每当我调用它时它会绑定新函数,或者它是否更新已经绑定的函数,还是在绑定新函数之前自动处理已绑定的函数…

简而言之:在使用$ .hover绑定新函数之前,我是否必须处置任何内容?

2)

我将按下状态的样式设置为文档样式,这意味着如果经常调用updateBackground函数,则文档头会被污染(每次其中一个文本字段在我的测试用例中触发blur-event)。

有没有更好的方法来实现相同的目标或者我可以在添加新的样式之前删除已设置的样式?

3)

如果由于按下样式中的!important-flag按下按钮,则不会出现hover状态的背景。 我不能只删除这个标志,因为如果没有它,压制状态的背景将无法正确显示…任何解决方案?

总的来说,我会对如何以完全不同的方式解决这个问题的每一个建议持开放态度。

谢谢,

MIK


编辑:

上面的代码只是一个例子。 实际上我需要能够更改其他分机控制的背景属性而不是按钮(面板,复选框,…)但我认为我可以自己采用按钮的工作解决方案到其他控件。

请记住这一点,不要在按钮上指定太多的答案。 它应该尽可能通用……

使用一些更具体的css选择器,您可以利用Ext的pressedCls和overCls配置。 http://docs.sencha.com/ext-js/4-1/#!/api/Ext.button.Button-cfg-pressedCls http://docs.sencha.com/ext-js/4-1/源极/ Button2.html#分机键式按钮-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(), }) 

编辑更动态,通用的解决方案

  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()); } } } }); 

既然你想要的东西不仅仅是按钮,那么它应该适用于任何组件。

以下是一个示例用法:

  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' }); 

好的,我刚刚找到了一个应该涵盖上述所有问题的解决方案:

我将两个, pressedhovered样式直接添加到标题中。

为了确保标题不会被污染,我只需要在添加新标题之前使用jQuery的分离函数动态删除样式元素。

工作实例

以及动态更改背景的代码:

 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(); $('').appendTo('head'); $('head style:contains("' + btn.id + '.x-btn-pressed")').detach(); $('').appendTo('head'); }; 

似乎为我工作,但我仍然愿意接受任何建议/改进!

谢谢。