2011-01-20 20 views
7

He notado un patrón común en el JavaScript que he estado escribiendo y me preguntaba si ya existe un patrón que defina algo similar como la mejor práctica. Básicamente, se trata de obtener un elemento DOM y envolverlo/asociarlo con un objeto JavaScript. Tome este ejemplo, donde necesita un filtro en su aplicación web. Su página es el siguiente:Envolviendo un elemento DOM dentro de un objeto JavaScript

<html> 
<head></head> 
<body> 
    <div id="filter"></div> 
</body> 
</html> 

Se podría entonces utilizar con el elemento de este modo:

var myFilter = new Filter({ 
    elem: document.getElementById('filter'), 
    prop: 'stacks-test', 
    someCallback: function() { 
     // specify a callback 
    } 
}); 

Y el código JavaScript (donde especificación es un objeto pasado al constructor):

var Filter = function(spec) { 
    this.elem = spec.elem; 
    this.prop = spec.prop; 
    this.callback = spec.someCallback; 
    this.bindEvents(); 
}; 

Filter.prototype.bindEvents = function() { 
    var self = this; 
    $(this.elem).click(function(e) { 
     self.updateFeed(); 
    }; 
}; 

Filter.prototype.updateFeed = function() { 
    this.prop; // 'stacks-test' 
    this.callback(); 
    // ... 
    // code to interact with other JavaScript objects 
    // who in turn, update the document 
}; 

¿Cómo se llama este tipo de enfoque y cuáles son las mejores prácticas y advertencias?

+0

No quiero sonar como un fan sin sentido de jQuery, pero * parece * que sería mejor usar jQuery o un marco similar. Si bien su objetivo principal es ayudarlo con la selección y manipulación de DOM, toda la biblioteca se basa en este patrón de envolvente de DOM del que está hablando, por lo que sus capacidades de complemento y otras funciones auxiliares naturalmente le facilitan la tarea. bien. –

+0

Todavía necesito usar constructores ya que habrá múltiples filtros en un documento. ¿Puedes mostrarme un ejemplo usando jQuery con el objeto Filter? –

+0

En breve publicaré una respuesta. Además, la próxima vez recuerde incluir @ Box9 en su comentario para recibir la notificación. Solo casualmente tropecé con esta pregunta. –

Respuesta

2

Puede que le interese la biblioteca de widgets de Dojo, Dijit; si entiendo su pregunta correctamente, básicamente hace lo que está pidiendo, y mucho más.

En Dijit, un widget esencialmente encapsula un nodo DOM, sus contenidos, cualquier JavaScript que defina su comportamiento, y (importado por separado) CSS para darle un estilo a su apariencia.

Los widgets tienen su propio ciclo de vida, registro y eventos (incluidos muchos que simplemente se relacionan con eventos DOM en un nodo dentro del widget, por ejemplo, myWidget.onClick podrían llamar efectivamente al myWidget.domNode.onclick).

Los widgets pueden (pero no tienen que) tener sus contenidos iniciales definidos en un archivo de plantilla HTML separado, mediante el cual también es posible vincular eventos en nodos dentro de la plantilla a métodos de widgets, así como establecer propiedades en widget que hace referencia a nodos particulares en la plantilla.

Apenas estoy arañando la superficie aquí. Si quieres leer más sobre esto, puede comenzar con estas páginas de referencia:

Dicho todo, no sé a qué apunta en última instancia, y tal vez esto es demasiado para sus propósitos (considerando que le estoy lanzando una biblioteca completa), pero pensó que podría despertar su interés al menos.

+0

+1, sin dudas, jQuery no es tan avanzado como otras bibliotecas en esta área. –

+0

Buena biblioteca, definitivamente me ha interesado. Sin embargo, estoy tratando de averiguar los detalles de implementación de bajo nivel de este patrón. Si guardo una referencia a un elemento DOM (un elemento contenedor de widgets quizás) como una propiedad de un objeto de función constructor, ¿cuáles son los desafíos y cosas para recordar? Una cosa que leí durante el fin de semana fue usar un método de vinculación en una función de clic para reducir la huella de la cadena de alcance para esos eventos. En esencia, espero encontrar lo que se llama este patrón para que pueda encontrar más material para leer. –

1

Continuando con mi comentario sobre la pregunta, jQuery es una herramienta potencial para el trabajo, ya que proporciona algunas de las bases para lo que buscas. Sin embargo, una vez dicho esto, introduce complejidades propias, y además, no todas las "formas jQuery" son iguales. Sugeriré una forma de usar jQuery como su "modelo de objeto", pero puede o no satisfacer sus necesidades.


Lo primero es lo primero. La filosofía de jQuery es comenzar todo seleccionando primero el elemento, usando $(), o equivalentemente jQuery(). Todas las operaciones comienzan conceptualmente con esto. Esta es una forma ligeramente diferente de pensar en comparación con la creación de un objeto que envuelve un elemento y mantiene una referencia a ese envoltorio, pero esencialmente esto es lo que jQuery hace por usted. Una llamada al $('#some-id') toma el elemento con id de "some-id" y lo envuelve en un objeto jQuery.


una manera: plugins Escribir "Filtro".

Reemplace su constructor con un método initFilter() jQuery. Puede hacerlo modificando el prototipo jQuery y utilizando el objeto jQuery como su envoltorio. El prototipo de jQuery es referenciado por jQuery.fn, por lo que:

jQuery.fn.initFilter = function (prop, callback) { 
    // Save prop and callback 
    this.data('filter-prop', prop); 
    this.data('filter-callback', callback); 

    // Bind events (makes sense to do this during init) 
    this.click(function() { 
     $(this).updateFeed(); 
    }); 
}; 

luego hacer una cosa similar para updateFeed():

jQuery.fn.updateFeed = function() { 
    this.data('filter-prop'); 
    this.data('filter-callback')(); 
}); 

y utilizarlo como esto:

$('#filter').initFilter(prop, callback); 

Tenga en cuenta que updateFeed puede ser simplemente alineado con el controlador de clics para evitar la contaminación innecesaria del espacio de nombres de jQuery. Sin embargo, una ventaja de usar jQuery de este modo es que no necesita mantener una referencia al objeto si necesita invocar alguna función más adelante, ya que jQuery relaciona todas las referencias con elementos reales. Si desea llamar updateFeed mediante programación, entonces:

$('#filter').updateFeed(); 

continuación, se invocará en el objeto correcto.


Algunas cosas a considerar

sin duda hay desventajas de este método. Una es que todas las propiedades, que hemos guardado contra el elemento usando .data(), se comparten entre todas las funciones de jQuery que actúan sobre ese elemento. Intenté aliviar esto prefijando los nombres de propiedad con "filter-", pero dependiendo de la complejidad de su (s) objeto (s), esto puede no ser adecuado.

Además, este método exacto puede no ser tan adecuado para objetos que requieren mucha manipulación (es decir, objetos con muchas funciones) ya que todas estas funciones se vuelven comunes a todos los objetos jQuery. Hay formas de encapsular todo esto, lo cual no entraré aquí, pero jQuery-ui hace esto con sus widgets, y estoy experimentando con otra alternativa más en una biblioteca que estoy creando.

Sin embargo, retrocediendo un poco, la única razón por la que sugerí usar jQuery en primer lugar es que su objeto Filter parece estar fuertemente relacionado con el DOM. Vincula eventos al DOM, modifica el DOM en función de la interacción del usuario, básicamente parece vivir en el DOM, por lo tanto, utilice algo basado en DOM, es decir, jQuery.

+1

Creo que el mayor problema aquí es, como dijiste, el alcance único para todas las propiedades de datos y, lo que es peor, el único alcance para todos los métodos. Utiliza el ámbito jQuery.fn para almacenar todas las funciones utilizadas por todos los objetos que puede arrojar a una página, lo que disminuye la portabilidad de un módulo. Si intentabas construir una página usando varias bibliotecas, tendrías que asegurarte de que ninguna de ellas tuviera métodos con el mismo nombre. Usando el patrón de objetos JS puede tener myapp.module.Filter.updateFilter y myapp.module.SpecialFilter.updateFilter sin preocuparse de que los dos entren en conflicto en jQuery.fn.updateFilter –

Cuestiones relacionadas