How to change background of hovered and pressed extjs-button dynamically

血红的双手。 提交于 2020-01-01 19:28:28

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!