Cómo cambiar el fondo del botón extjs sobrevolado y presionado dinámicamente

Hy allí,

Necesito la capacidad de cambiar el color de fondo para los diferentes estados (normal, flotante, presionado) de un botón dinámicamente.

Lo que se me ha ocurrido hasta ahora es lo siguiente: 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();
});

Esto funciona básicamente, pero me quedan algunas preguntas:

1)

¿Está bien llamar a la función de desplazamiento de jquery cada vez que se llama al método updateBackground?

De acuerdo con jquery-doc (http://api.jquery.com/hover/) esta función vincula las 2 funciones dadas a los eventos mouse-enter- & mouse-leave-events del elemento dado.

¿Significa esto que vincula nuevas funciones cada vez que lo llamo o actualiza las ya vinculadas o elimina las ya vinculadas automáticamente antes de vincular las nuevas...

En resumen: ¿tengo que desechar algo antes de vincular las nuevas funciones con $ .hover?

2)

Configuré el estilo para el estado presionado como estilo de documento, lo que significa que el encabezado del documento se contamina si se llama a menudo a la función de actualización de fondo (cada vez que uno de los campos de texto activa el evento de desenfoque en mi caso de prueba).

¿Hay alguna forma mejor de lograr el mismo objetivo o puedo eliminar los estilos ya establecidos antes de agregar otros nuevos?

3)

El fondo para el estado de desplazamiento no aparece si se presiona el botón debido a la bandera !importante en el estilo presionado. No puedo simplemente eliminar esta bandera porque el fondo del estado presionado no se mostraría correctamente sin ella... ¿Alguna solución?

En general, estaría abierto a cualquier sugerencia sobre cómo resolver este problema de una manera completamente diferente.

Gracias,

mik


Edit:

El código anterior es solo un ejemplo. En realidad, también necesito poder cambiar el atributo de fondo para otros controles externos además de los botones (paneles, casillas de verificación, ...), pero creo que puedo adoptar una solución funcional para los botones para esos otros controles.

Tenga esto en cuenta y no especifique demasiado la respuesta en los botones. Debe ser lo más genérico posible...

preguntado el 24 de agosto de 12 a las 10:08

2 Respuestas

Usando algunos selectores css más específicos, puede aprovechar las configuraciones pressedCls y overCls de Ext. 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(),
})

Edite para una solución genérica más dinámica

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

Dado que desea algo que funcione en algo más que un botón, esto debería funcionar en cualquier componente.

Aquí hay un ejemplo de uso:

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

Respondido 28 ago 12, 01:08

Necesito poder cambiar el css dinámicamente durante el tiempo de ejecución para los controles creados dinámicamente (en realidad, no solo los botones como en el ejemplo anterior). - Suamikim

@suamikim su pregunta solicita específicamente ayuda con los estados de los botones. Si necesita más ayuda que los estados de los botones, actualice su pregunta o publique otra. - por favor

Ok, agregué una nota al final, pero lo más importante es que necesito poder cambiar el fondo dinámicamente. - Suamikim

Perfecto. La parte editada es exactamente lo que estaba buscando y parece ser mejor que mi solución, ya que solo usa herramientas estándar ext hasta donde puedo ver. Gracias - Suamikim

Ok, acabo de encontrar una solución que debería cubrir todos los problemas descritos anteriormente:

Agrego ambos, el pressed y hovered estilo directamente al encabezado.

Para asegurarme de que el encabezado no se contamine, simplemente elimino los elementos de estilo dinámicamente con jQueryLa función de separación del encabezado antes de agregar otros nuevos.

Ejemplo de trabajo

Y el código para el cambio dinámico del fondo:

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

¡Parece funcionar para mí, pero todavía estoy abierto a cualquier sugerencia/mejora a esto!

Gracias.

Respondido 27 ago 12, 20:08

No estoy realmente seguro de cómo esto es mejor que mi solución, supongo que para cada uno. Crear el css en javascript requiere mucho trabajo adicional y no aprovecha el almacenamiento en caché del navegador. Su solución utiliza identificadores codificados, lo que dificulta su mantenimiento. Su solución es realizar consultas de componentes para obtener referencias, lo cual es un trabajo adicional que no es necesario. Su solución es usar jQuery dentro de Ext, que es un no, no. Sus soluciones también salen de la Ext api provista para agregar clases css a los botones al presionar y pasar el mouse. - por favor

@pllee Como se dijo antes, necesito una solución que pueda cambiar el estilo DINÁMICAMENTE y no veo cómo podría lograrse esto con su solución porque usa clases css creadas y asignadas estáticamente. Agregue un comentario arriba y muéstreme cómo funcionaría dinámicamente su solución porque simplemente no la veo... Gracias. Suamikim

Lo siento, pensé en clases dinámicas de css en el botón como new Ext.Button({overCls: 'red-button'); new Button({overCls: 'yellow-button'}); hubiera sido suficiente. - por favor

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.