Convertir código jQuery en un complemento

Cuando se trata de organizar eficientemente el código jQuery, una de las mejores opciones es convertir ciertas partes en un complemento. Esto tiene muchos beneficios:su código se vuelve más fácil de modificar y seguir, y las tareas repetitivas se manejan de forma natural. Esto también mejora la velocidad con la que desarrolla, ya que la organización de complementos promueve la reutilización del código.

Es por eso que hoy vamos a demostrar el proceso de convertir código en un complemento. Tomaremos el código de nuestro tutorial jQuery &CSS3 Select Replacement y lo convertiremos en un complemento jQuery listo para usar.

La idea

Escribir un complemento jQuery no es nada difícil. Necesita extender el $.fn objeto con su propia función. Sin embargo, lo que es más difícil es encontrar una manera de estructurar correctamente su código para que su complemento sea fácil de incrustar y usar, sin dependencias.

Aquí hay varios problemas que debemos resolver al convertir el código del tutorial en un complemento de jQuery:

  1. Necesitamos dar a los usuarios la capacidad de controlar qué marcado se genera para el menú desplegable. Por ejemplo, el código del tutorial se basa en gran medida en la presencia de data- atributos, que contienen marcado HTML. Esto es demasiado específico para incluirlo en un complemento, por lo que debemos dejarlo fuera de la implementación;
  2. Debido a la forma en que se llaman los complementos, necesitamos reescribir el código para que use el objeto "this" que se pasa al complemento, en lugar de codificar un selector. Esto también permitirá convertir más de un elemento seleccionado a la vez;
  3. Necesitamos extraer el código JavaScript y CSS del complemento en archivos separados, para que sea fácil de incrustar y redistribuir.

El Código

Como recordará del tutorial, nuestro código jQuery escanea los elementos de opción de selección y crea una lista desordenada. En el proceso, también busca una serie de atributos de datos en las opciones que contienen una URL de imagen y una descripción para usar en la lista.

Sin embargo, esto es demasiado específico para un complemento. Necesitamos dar a los usuarios la capacidad de anular esta funcionalidad. Para resolver el problema, podemos permitir que los usuarios pasen una función como parámetro al complemento, que generará el marcado en su lugar. Si no se pasa dicho parámetro, utilizaremos el recurso predeterminado, que básicamente toma el texto del elemento de opción y lo convierte directamente en un elemento de lista.

Pongamos esto en código:

(function($){

    $.fn.tzSelect = function(options){
        options = $.extend({
            render : function(option){
                return $('<li>',{
                    html : option.text()
                });
            },
            className : ''
        },options);

    // More code will be added here.

    }
})(jQuery);

La función de representación toma un elemento de opción (del tipo que está contenido en un select ) y devuelve un elemento li, que el complemento incluye directamente en la lista desplegable. Esto resuelve el problema n.º 1 descrito anteriormente.

Antes de continuar con la solución del problema #2 , veamos cómo se llamará nuestro complemento:

$(document).ready(function(){
    $('select').tzSelect();
});

En el código de ejemplo anterior, puede ver que estamos aplicando el complemento a cada selección elemento en la página. Podemos acceder a estos elementos atravesando el "esto " objeto que se pasa al complemento:

return this.each(function(){

            // The "this" points to the current select element:

            var select = $(this);

            var selectBoxContainer = $('<div>',{
                width       : select.outerWidth(),
                className   : 'tzSelect',
                html        : '<div class="selectBox"></div>'
            });

            var dropDown = $('<ul>',{className:'dropDown'});
            var selectBox = selectBoxContainer.find('.selectBox');

            // Looping though the options of the original select element

            if(options.className){
                dropDown.addClass(options.className);
            }

            select.find('option').each(function(i){
                var option = $(this);

                if(i==select.attr('selectedIndex')){
                    selectBox.html(option.text());
                }

                // As of jQuery 1.4.3 we can access HTML5
                // data attributes with the data() method.

                if(option.data('skip')){
                    return true;
                }

                // Creating a dropdown item according to the
                // data-icon and data-html-text HTML5 attributes:

                var li = options.render(option);

                li.click(function(){

                    selectBox.html(option.text());
                    dropDown.trigger('hide');

                    // When a click occurs, we are also reflecting
                    // the change on the original select element:
                    select.val(option.val());

                    return false;
                });

                dropDown.append(li);
            });

            selectBoxContainer.append(dropDown.hide());
            select.hide().after(selectBoxContainer);

            // Binding custom show and hide events on the dropDown:

            dropDown.bind('show',function(){

                if(dropDown.is(':animated')){
                    return false;
                }

                selectBox.addClass('expanded');
                dropDown.slideDown();

            }).bind('hide',function(){

                if(dropDown.is(':animated')){
                    return false;
                }

                selectBox.removeClass('expanded');
                dropDown.slideUp();

            }).bind('toggle',function(){
                if(selectBox.hasClass('expanded')){
                    dropDown.trigger('hide');
                }
                else dropDown.trigger('show');
            });

            selectBox.click(function(){
                dropDown.trigger('toggle');
                return false;
            });

            // If we click anywhere on the page, while the
            // dropdown is shown, it is going to be hidden:

            $(document).click(function(){
                dropDown.trigger('hide');
            });

        });

El fragmento de arriba es casi idéntico al código del tutorial que estamos convirtiendo hoy. Un cambio notable es que asignamos $(this) a la variable de selección (línea 5), ​​que solía ser $('select.makeMeFancy') (un selector codificado), que limitó significativamente el alcance del código.

El otro cambio es que, en lugar de generar directamente la lista desplegable, llamamos a la función de representación que se pasó como parámetro (línea 51).

Cuando combinamos lo anterior, obtenemos el código fuente completo del complemento:

tzSelect/jquery.tzSelect.js

(function($){

    $.fn.tzSelect = function(options){
        options = $.extend({
            render : function(option){
                return $('<li>',{
                    html : option.text()
                });
            },
            className : ''
        },options);

        return this.each(function(){

            // The "this" points to the current select element:

            var select = $(this);

            var selectBoxContainer = $('<div>',{
                width       : select.outerWidth(),
                className   : 'tzSelect',
                html        : '<div class="selectBox"></div>'
            });

            var dropDown = $('<ul>',{className:'dropDown'});
            var selectBox = selectBoxContainer.find('.selectBox');

            // Looping though the options of the original select element

            if(options.className){
                dropDown.addClass(options.className);
            }

            select.find('option').each(function(i){
                var option = $(this);

                if(i==select.attr('selectedIndex')){
                    selectBox.html(option.text());
                }

                // As of jQuery 1.4.3 we can access HTML5
                // data attributes with the data() method.

                if(option.data('skip')){
                    return true;
                }

                // Creating a dropdown item according to the
                // data-icon and data-html-text HTML5 attributes:

                var li = options.render(option);

                li.click(function(){

                    selectBox.html(option.text());
                    dropDown.trigger('hide');

                    // When a click occurs, we are also reflecting
                    // the change on the original select element:
                    select.val(option.val());

                    return false;
                });

                dropDown.append(li);
            });

            selectBoxContainer.append(dropDown.hide());
            select.hide().after(selectBoxContainer);

            // Binding custom show and hide events on the dropDown:

            dropDown.bind('show',function(){

                if(dropDown.is(':animated')){
                    return false;
                }

                selectBox.addClass('expanded');
                dropDown.slideDown();

            }).bind('hide',function(){

                if(dropDown.is(':animated')){
                    return false;
                }

                selectBox.removeClass('expanded');
                dropDown.slideUp();

            }).bind('toggle',function(){
                if(selectBox.hasClass('expanded')){
                    dropDown.trigger('hide');
                }
                else dropDown.trigger('show');
            });

            selectBox.click(function(){
                dropDown.trigger('toggle');
                return false;
            });

            // If we click anywhere on the page, while the
            // dropdown is shown, it is going to be hidden:

            $(document).click(function(){
                dropDown.trigger('hide');
            });

        });
    }

})(jQuery);

Colocar este complemento en un archivo separado resuelve el problema #3 . Sin embargo, como mencioné anteriormente, omitimos intencionalmente el código que usa el data- atributos para hacer que el complemento sea más portátil. Para compensar, necesitamos pasar una función de representación personalizada al llamar al complemento, como puede ver a continuación (este también es el código que se usa en la demostración).

secuencia de comandos.js

$(document).ready(function(){

    $('select.makeMeFancy').tzSelect({
        render : function(option){
            return $('<li>',{
                html:   '<img src="'+option.data('icon')+'" /><span>'+
                        option.data('html-text')+'</span>'
            });
        },
        className : 'hasDetails'
    });

    // Calling the default version of the dropdown
    $('select.regularSelect').tzSelect();

});

¡Con esto, nuestro complemento jQuery está completo!

Conclusión

Siguiendo estos sencillos pasos, puede convertir fácilmente un lío de código jQuery en un complemento estructurado y listo para reutilizar. Claro, requiere un poco de trabajo, pero el esfuerzo valdrá la pena muchas veces a largo plazo.