Comunidad de diseño web y desarrollo en internet

Crear plugins para jQuery

jQuery, uno de los mejores frameworks para Javascript y AJAX que existen, puede ser facilmente extendido usando plugins. En este tutorial te mostraré como crear plugins para jQuery, desde lo más básico hasta la integración directa con la libreria.

El propósito de este tutorial es aprender a crear plugins para jQuery, con las facilidades que la libreria ya trae. Antes de empezar te recomiendo leer el tutorial de introduccion a jQuery, si no conoces los conceptos basicos del lenguaje, y el tutorial de programacion orientada a objetos en javascript, para que entiendas como ocurre todo a la perfeccion.

Objetos a extender

Para la creacion de plugins con jQuery, hay dos objetos básicos que se extenderan: El objeto jQuery, que se encarga de practicamente todo el procesamiento interno y el objeto jQuery.fn, que es el que maneja la interaccion con elementos.

Si quisieramos crear una función general, usariamos jQuery, pero si quisieramos hacer uso de la potencia de los selectores built-in, usariamos jQuery.fn.

Creando el espacio de trabajo

Lo primero que tenemos que hacer es preparar un area de trabajo: Primero decidimos de que se tratará nuestro plugin. Con proposito de hacerlo sencillo creemos un plugin que alerte el texto (contenido) de un elemento cualquiera de diferentes formas. Acto seguido, creamos un archivo con el siguiente formato de nombre: jquery.nombre_del_plugin.js . Eso ayuda a identificarlo como plugin de jQuery.

Despues, creemos un archivo HTML en el que vinculamos la librería jQuery y nuestro plugin (que por ahora esta vacio). Ahora, abramos nuestro plugin en nuestro editor favorito (de texto plano, nada de Word), y comencemos la diversion.

Creando el objeto principal, sus metodos y propiedades

Vamos a crear dos tipos de funciones, cada una con uno de los objetos a extender, solo por aprendizaje. De esta manera, escribamos en nuestro archivo lo siguiente:

jQuery.comprobarAlert = function( mensaje ){
    alert(mensaje);
}


jQuery.fn.alerter = function(){
    this.each( function(){
        alert(this);
    });
}

Analizemos esas funciones: La primera está extendiendo el objeto jQuery, creando una función con el nombre de comprobarAlert, cuyo propósito es muy simple: Pasar un parametro de mensaje, que sera alertado. Para probar la función vamos a nuestro HTML y añadimos las siguientes lineas a un tag script:

$(document).ready( function(){
    $.comprobarAlert("Hola!");
});

Eso tiene que alertarnos "Hola!".

La segunda función es algo más completa. Cuando usamos jQuery.fn, el this hace referencia a un objeto jQuery que tiene "dentro" todos los elementos que recopila el selector. Entonces el each hace un bucle ejecutando la función para cada elemento, en este caso, alertando el objeto encontrado (todos los objetos encontrados, de hecho :P )

Para una representacion no tan abstracta, usemos un ejemplo concreto. Si en nuestro documento HTML tenemos lo siguiente ...

$(document).ready( function(){
    $("#victima").alerter();
});

... lo que le estamos diciendole al plugin es: Busca todos los elementos que tengan como id victima, y recogelos en una "lista" jquery. Luego, por cada elemento de esta lista, haz la función indicada, que es alertar el objeto (con alerter() ).

Nota: Es importante entender bien los ámbitos del this: Dentro de la función principal, el this hace referencia a la lista, mientras que dentro del each, el this hace referencia al elemento DOM ya seleccionado.

Extendiendo el plugin: Opciones

Ya tenemos la idea basica de como nombrar un plugin y ponerlo a funcionar. Ahora examinemos como podemos hacer que el plugin tenga opciones, para que el usuario defina su comportamiento como mejor le parezca.

Nota: Los codigos que aparecen a continuacion se ubican o bien en el archivo del plugin o en el documento HTML (en cada caso se especifica). Se sobreentenderá que lo que aparece en el HTML está dentro de $(document).ready(), es decir, que funciona cuando el DOM se ha cargado. Tambien pueden haber continuas referencias a un selector "#victima", correspondiente a un div en nuestro documento HTML ( que debemos crear )

Añadamos a nuestro plugin de alerta la posibilidad de enviar una cadena adicional al comienzo y al final de el mensaje, sin que estos parametros adicionales sean obligatorios. Hay dos opciones: La primera es usar jQuery.extend, una función built-in de jQuery, pensada para proveer variables con valores "default", modificables por el usuario. La segunda es hacerlo sin ayuda de extend, que puede ser más entendible.

Primera opción:

jQuery.comprobarAlert = function( mensaje, opciones_user ){

    opciones_default = {
        inicio_str : "Alerta: ",
        final_str: " /fin "
    }
    opciones = jQuery.extend(opciones_default , opciones_user);     alert(opciones.inicio_str + mensaje + opciones.final_str); }

Segunda opción:

jQuery.comprobarAlert = function( mensaje, opciones_user ){
    if( opciones_user == undefined ){
        opciones = ({
            inicio_str : "Alerta: ",
            final_str: " /fin "
        });
    }else{
        opciones = opciones_user;
    }
    alert(opciones.inicio_str + mensaje + opciones.final_str);
}

La primera opcion es un poco abstracta pero es más compacta. La explicación es la siguiente: Para crear la variable opciones se llama jQuery.extend. Esta función asigna los valores del primer parametro a la variable si el segundo parametro esta vacio o es "undefined" (no esta definido). De tal manera, si el usuario no ingresa opciones se toman las predeterminadas, y si las ingresa, se sobreescriben.

La segunda opcion es mas o menos la explicacion de la primera: Se comprueba si el usuario mando opciones. Si no es asi, se toman las predeterminadas. Si el usuario mandó, se toman estas.

Es importante notar que las opciones quedan como propiedades del objeto "opciones", es decir, que para acceder a "inicio_str" tenemos que escribir "opciones.inicio_str". Para el resto del tutorial usaremos la primera forma, por la razón a continuación.

Usabilidad:

Si queremos que el usuario tenga control total del plugin, debemos proveer la capacidad de cambiar tanto los defaults para un llamado, como para todo el documento. Veamos este ejemplo de llamados:

// Aqui el mensaje va con opciones normales

$.comprobarAlert("Tengo opciones default");

// Aqui podemos cambiar el default:
$.comprobarAlert.op_default.inicio_str = "Wii: ";

//Y ejecutar el mismo llamado, que ahora dara un resultado distinto:
$.comprobarAlert("Tengo opciones default");

Esto es particularmente útil para ser aplicado en escenarios diversos de manera sencilla. Supón que tienes un plugin que cambie el fondo de un elemento. El autor del plugin definió que el color normal de fondo es amarillo, pero tu pagina web es de tonos ocres, asi que te interesa que el color sea verde. Si no puedes controlar los defaults desde tu web, cada vez que quieras usar el codigo, deberás cambiar la llamada:

$("a").colorizar("fondo", ({
    color: "verde"
});
$("body").colorizar("borde", ({
    color: "verde"

});

En vez de eso, podrias hacer lo siguiente (con el metodo que ya casi explicaré):

$.colorizar.opciones.color = "verde":
$("a").colorizar("fondo");
$("body").colorizar("borde");

//E incluso, puedes cambiar el color de uno solo con el override (reemplazo) que ya hemos visto:
$("p").colorizar("texto", {
    color:"naranja"
});

La manera de lograr esta maravilla de la usabilidad (XD) es la siguiente (con nuestro ejemplo de alerter):

jQuery.comprobarAlert = function( mensaje, opciones_user ){

    // Primero creamos nuestra variable de opciones
    var opciones = jQuery.extend( jQuery.comprobarAlert.op_default , opciones_user);
    alert(opciones.inicio_str + mensaje + opciones.final_str);

}

jQuery.comprobarAlert.op_default = {
    inicio_str : "Alerta: ",
    final_str: " /fin "
}

Como verás, hemos dividido en dos la función. Al separar "jQuery.comprobarAlert.op_default" hacemos que esté accesible desde cualquier parte. Asi que, como ya vimos, bastaría substituir el contenido de la variable para cambiar los defaults:

$.comprobarAlert.op_default{
    inicio_str : "He reemplazado al default: ",
    final_str: ". Oh si."
}

o incluso cambiarlos por separado:

$.comprobarAlert.op_default.inicio_str = "Solo reemplazo el primer default";

Extensibilidad

Si queremos que el usuario final tenga todas las comodidades para usar nuestro plugin, podemos añadirle la extensibilidad. Si, digamos, nuestro plugin usara una función interna que transformara el texto de alguna manera, podemos tambien proveer una función "default", que el usuario pueda cambiar si necesita. Miremos el ejemplo:

jQuery.comprobarAlert = function( mensaje, opciones_user ){
    var opciones = jQuery.extend( jQuery.comprobarAlert.op_default , opciones_user);
    // Aqui se llama a la función, que definimos externamente
    var mensaje = jQuery.comprobarAlert.transformar(mensaje);
    alert(opciones.inicio_str + mensaje + opciones.final_str);
}

jQuery.comprobarAlert.op_default = {
    inicio_str : "Alerta:",
    final_str: " /fin "
}

// Esta es nuestra "función modificable"
jQuery.comprobarAlert.transformar = function(texto){
    return String( texto ).toUpperCase();
};

Como verás, estamos dejando que el contenido de la función sea modificable, de modo que podamos poner en nuestro html un reemplazo:

jQuery.comprobarAlert.transformar = function(texto){

    return String( texto ).toLowerCase();

};

Por supuesto, hay que escoger bien las funciones que serán "abiertas": No se debe comprometer el funcionamiento del plugin. Para crear funciones que sean privadas, haremos lo que se muestra en el tutorial de poo en javascript:

//...
jQuery.comprobarAlert = function( mensaje, opciones_user ){
    var opciones = jQuery.extend( jQuery.comprobarAlert.op_default , opciones_user);

    function transformar(msj){
        return String( msj ).toUpperCase();
    }
    // Aqui se llama a la función, que es privada     var mensaje = transformar(mensaje);     alert(opciones.inicio_str + mensaje + opciones.final_str); } //...

De ese modo, nuestra función es inaccesible externamente.

Extendiendo el objeto jQuery

Hasta ahora hemos visto como modificar todos los aspectos de nuestro objeto plugin, ahora vamos a modificar el objeto jQuery.

Cuando a la función jQuery.extend se le pasa solo un parametro, y este es un objeto, esta extiende lo que la llamó. Esto nos permite por ejemplo, añadir un nuevo evento:

/* Si existieran pantallas holograficas donde los objetos fueran 3D y se 
pudiera dar el siguiente evento built-in en un browser... sighs. */

jQuery.fn.rozar = function(fun){
    return this.each(
        // XD, IE demorará mucho implementando esto:
        this.onrub = this.apply( fun );
    );
};

// Y lo anterior se puede usar como

$(".holocube3dsuperdelux").rozar( function(){
    $(this).css("z-index","3000");
});

Por supuesto, el evento usado arriba (onrub) y el escenario en si, son totalmente ficticios, pero la idea es que se entienda lo que se quiere lograr ;)

Uso del alias $

Hasta ahora en los codigos vistos, se ha hecho un gran uso del jQuery.talcosa, en vez de $.talcosa. Usar "jQuery.*" es beneficioso: Si el usuario tiene dos librerias js (algunas usan el $ tambien), jQuery no entrará en conflicto. Sin embargo usar solo "jQuery.*" es muy embarazoso para algunos, asi que hay una forma de usarlo en todos lados sin perder la compatibilidad con otros frameworks: Encapsular funciones.

Si antes teniamos un codigo como:

jQuery.comprobarAlert = function( mensaje, opciones_user ){

    var opciones = jQuery.extend( jQuery.comprobarAlert.op_default , opciones_user);
    var mensaje = jQuery.comprobarAlert.transformar(mensaje);
    alert(opciones.inicio_str + mensaje + opciones.final_str);

}

Eso se transforma a:

(function($) {
     $.comprobarAlert = function( mensaje, opciones_user ){
        var opciones = $.extend( $.comprobarAlert.op_default , opciones_user);
        var mensaje = $.comprobarAlert.transformar(mensaje);
        alert(opciones.inicio_str + mensaje + opciones.final_str);
    }
})(jQuery);

con el uso del alias $, que es mas elegante y compacto. En resúmen:

(function($) {
 // Aqui pones tu codigo, el cual puede hacer uso de $ .... y $ = :)
})(jQuery);

Juntandolo todo:

Ahora que hemos visto todo ( o bastante de ) lo relacionado con plugins en jQuery, finalizemos nuestro cool plugin de comprobarAlert. Voy a cambiarle el nombre por uno corto (alerter) y lo implementaré como una extension al jQuery.fn, para usar selectores con él:

( function($) {
    $.fn.alerter = function(atributo, opciones_user){

        // Ponemos la variable de opciones antes de la iteración (each) para ahorrar recursos
        opc = $.extend( $.fn.alerter.opc_default, opciones_user );

        // Devuelvo la lista de objetos jQuery
        return this.each( function(){
            var atrib = $(this).attr(atributo);
            var mensaje = $.fn.alerter.formato(atrib);
            alert( opc.inicial_str + mensaje + opc.final_str );
        });

    };

    $.fn.alerter.opc_default = {
        inicial_str : "Mensaje: "
        final_str : "."
    };

    $.fn.alerter.formato = function(texto){
        var texto = String(text);
        var primera_letra = texto.substring(0,1);
        var resto = texto.substring(1, texto)length);
        return primera_letra+resto;
    };
})(jQuery);

Con eso podemos desde nuestro html hacer el llamado:

$("#victima").alerter("id");

Lo que nos retornará "Mensaje: victima.". Si sobreescribimos los defaults con la siguiente llamada:

$.fn.alerter.formato = function(texto){
    return String(texto).toUpperCase();
};

$("#victima").alerter("id", {
    inicial_str: "Alerta:",
    final_str: " ."
});

Nos retorna "Alerta:VICTIMA .".

Resumen / puntos a recordar:

  • Nombrar el plugin jquery.nombre.js
  • Los métodos se añaden al objeto jQuery.fn, y las funciones al objeto jQuery.
  • Tener en cuenta los ámbitos de las variables en el plugin (explicados arriba).
  • Todos los metodos y funciones DEBEN terminar con ; o el codigo no funcionara al comprimirse.
  • Los métodos deben devolver el objeto jQuery (a menso de que se especifique lo contrario).
  • Se debe hacer ciclo con los elementos usando "this.each", para producir codigo limpio y compatible.
  • Siempre usar "jQuery" en vez de $ a menos de que se coloque la solucion ya mostrada.

Tambien hay un patron de desarrollo, propuesto por Mike Alsup, que trata de los puntos más importantes que hemos visto:

  • Usar un solo nombre en el objeto jQuery: No satures el objeto jQuery o jQuery.fn con muchos objetos distintos para un solo plugin. Usa solo un nombre (objeto), al cual le añades métodos y propiedades
  • Aceptar un argumento de "opciones" para controlar el plugin
  • Proveer una manera de modificar los valores default del plugin.
  • Proveer acceso a modificar funciones del plugin cuando sea posible
  • Mantener las funcione principales privadas.
  • Soporte del plugin Metadata (no cubierto en este tutorial, escribiré en el futuro sobre este)

Referencia:

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

El autor de este artículo ha cerrado los comentarios. Si tienes preguntas o comentarios, puedes hacerlos en el foro

Entra al foro y participa en la discusión

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate