2009-10-08 12 views
25

¿Cómo creo un plugin de jQuery para que pueda usar espacios de nombres en mi complemento?jQuery Plugin Namespace

$("#id1").amtec.foo1(); 
$("#id1").amtec.foo2(); 

Ninguno de estos parece funcionar.

(function($) { 
    var amtec = { 
     $.fn.foo1 : function(){ return this.each(function(){}); }, 
     $.fn.foo2 : function(){ return this.each(function(){}); } 
     }; 

    })(jQuery); 
(function($) { 
    $.fn.amtec = function(){ 
     var foo1 = function(){ return this.each(function(){}); }; 
     var foo2 = function(){ return this.each(function(){}); }; 
     } 
    })(jQuery); 
+0

por favor, echa un vistazo a mi solución. es más preciso para lo que estás tratando de lograr. –

Respuesta

21
(function($) { 
    $.fn.amtec = function() { 
     var jq = this; 
     return { 
      foo1: function(){ 
       return jq.each(function(){}); 
      }, 

      foo2: function(){ 
       return jq.each(function(){}); 
      } 
     } 
    }; 
})(jQuery); 
+0

Alexander, la consola de error en FireBug muestra: this.each no es una función – MotionGrafika

+0

Creo que he estropeado las cosas - He actualizado mi respuesta. –

+4

Muchas gracias Alexandar! Funciona pero como $ ("# id1"). Amtec(). Foo1(); y no como $ ("# id1"). Amtec.foo2(); – MotionGrafika

3
(function($){ 
    $.namespace = function(ns, functions){ 
    $.fn[ns] = function() {return this.extend(functions)}; 
    }; 
    $.namespace('$', $.fn); // the default namespace 
})(jQuery); 

Así que ahora usted puede tener un plugin:

$.fn.func = function(){alert('plugin'); return this'}; 

y crear plugins en un espacio de nombres:

$.namespace ('mynamespace', { 
    func: function() {alert('namespaced plugin'); return this;}, 
    otherfunc: function() {return this.css('color', 'yellow');} 
}); 

Y si lo hace

$('div').func(); // alerts 'plugin' -- no namespace 

Pero

$('div').mynamespace().func(); // alerts 'namespaced plugin' 

Y

$('div').mynamespace().func().$().func(); // alerts 'namespaced 

plug-in, entonces se restablece a la jQuery normal y alerta 'plug-in'

+1

Para llamar a otherFunc sería jsut ser $ (div) .mynamespace.otherFunc(); ? – Chris

+1

Tenga cuidado con esto. Respuesta inteligente, pero se comporta más como el [Pattern Decorator] (http://en.wikipedia.org/wiki/Decorator_pattern) que un Namespace. Eso podría causarle problemas si no está familiarizado con los pros y los contras habituales de ese patrón. – colllin

2

Sé que es una vieja pregunta ... ¿Pero por qué escribir todo este código extra cuando puede simplemente reemplazar . con _?

$.fn.amtec_foo1 = function(){ return this.each(function(){}); } 
$.fn.amtec_foo2 = function(){ return this.each(function(){}); } 

Mejor aún, dar a su plugin de un nombre que es original, & proyecto agnóstico.

$.fn.fooize = function(){ return this.html('Element has been Fooized!'); } 
+0

Eso poluta el espacio de nombres, y no se ve nada bien. – WhyNotHugo

+0

refrescante y pragmático. ¡Gracias! – colllin

12

Sé que estoy casi tres años tarde a la fiesta, pero espero que los futuros lectores de esta pregunta se pueden beneficiar de mi respuesta. La respuesta por GSto se ve muy bien desde el punto de vista del diseño de un plugin jQuery, pero tiene un pequeño problema: llamar al mynamespace() corta la instancia de jQuery devuelta con nuevos métodos. Aquí es un ejemplo de que sea un problema:

$myDiv = $('.mydiv'); 
$myDiv.mynamespace().height(); // this will be `height' from mynamespace 
$myDiv.height();    // this will STILL be `height' from mynamespace 
           // because it has overwritten $myDiv.height 

La respuesta elegida no tiene este problema porque hay amtec() no es una instancia de jQuery y es en cambio un objeto que llama a sus métodos con el ejemplo jQuery como contexto. He tomado los conceptos de ambas respuestas y escrito el plugin espacio de nombres a continuación:

(function($) { 
    $.namespace = function(namespaceName, closures) { 

    if ($.fn[namespaceName] === undefined) { 
     $.fn[namespaceName] = function executor(context) { 
     if (this instanceof executor) { 
      this.__context__ = context; 
     } 
     else { 
      return new executor(this); 
     } 
     }; 
    } 

    $.each(closures, function(closureName, closure) { 
     $.fn[namespaceName].prototype[closureName] = function() { 
     return closure.apply(this.__context__, arguments); 
     }; 
    }); 

    }; 
})(jQuery); 

Ejemplo de uso:

$.namespace('milosz', { 
    redify: function() { 
     $(this).css('color', '#ff0000'); 
    }, 
    greenify: function() { 
     $(this).css('color', '#00ff00'); 
    } 
}); 

$.namespace('milosz', { 
    blueify: function() { 
     $(this).css('color', '#0000ff'); 
    } 
}); 

$('.mydiv').milosz().redify(); // The HTML elements with class `mydiv' are now red 

El código utiliza algunos detalles bonitos de bajo nivel de JavaScript que están bien explicadas por John Resig's Advanced JavaScript tutorial, pero hablando vagamente lo que está sucediendo en el ejemplo es la siguiente:

Cuando se llama milosz (internamente $.fn[namespaceName]), this apunta a la jQuery ejemplo volvieron b y $('.mydiv').Por lo tanto, la instrucción if cae al bloque else y se llama a la versión de constructor de milosz (referida internamente como executor por razones que están a punto de hacerse evidentes). Al constructor se le pasa un único parámetro: this, un puntero al jQuery la instancia que va a ser el contexto de ejecución para todos los miembros del espacio de nombres milosz. Volvemos a ingresar a la instrucción if, esta vez ejecutando el primer bloque, donde la instancia jQuery que se ha pasado al pasado se almacena en una variable miembro llamada __context__ (que con suerte tiene pocas posibilidades de sobrescribirse). Se devuelve el objeto construido, completo con una referencia a la instancia original jQuery y cualquier envoltorio agregado a su prototipo mediante invocaciones de $.namespace. Estos contenedores simplemente ejecutan los métodos pasados ​​en el espacio de nombres milosz con el objeto original jQuery como contexto, como ocurre cuando se ejecuta redify.

Bah, sé que es un bocado, de todos modos el punto es que funciona como la respuesta aceptada, pero se parece a la respuesta jQueryish, que para mí es lo mejor de ambos mundos.

+1

Gran enfoque, gracias de un año después, tres años después de la fiesta. – cmsjr

+1

Usaré esta técnica en mi nueva biblioteca de fábrica de complementos jQuery. Me duele la cabeza, pero funciona! –

+0

Sé que ha pasado un tiempo, pero este método no me permite llamar a una función como $ .myNamespace(). Function() - pero funciona como $(). MyNamespace(). Function() - cualquiera tiene una solución a esto? –

1
$.cg = { 
    foo1: function(weq){ 
     return console.log(weq); 
    }, 
    foo2: function(rw){ 
     return console.log(rw); 
} 
}; 
$.cg = { // will result in error because $.cg is already declared above 

    foo4: function(rw){ // will result in error 
     return console.log(rw); // will result in error 
} // will result in error 
}; // will result in error 

$.cg.foo3 = function(weq){ //to add anything new to $.cg , you have to do it this way. 
     return console.log(weq); 
    } 

$.cg.foo1("12"); 
$.cg.foo2("22"); //works fine. 
$.cg.foo3("112"); //works fine. 
+0

El problema con esto es que las funciones no recibirán el selector jQuery dentro del contexto 'this'. –