javascript - change - title css
gestión de eventos documentados en un sitio web a gran escala (9)
NOTA: ahora he creado un complemento jQuery que es mi intento de encontrar una solución a este problema. Estoy seguro de que podría mejorarse y probablemente he pasado por alto muchos casos de uso, por lo que si alguien quiere dar su opinión, no dude en :-) https://github.com/WickyNilliams/ReadyBinder
No tengo un problema como tal, pero pensé que este sería un punto interesante para la discusión, y espero que la gente tenga algunas ideas interesantes para esto.
Básicamente, trabajo en un sitio web a gran escala y cada vez escribo más y más JavaScript. Esto está bien, disfruto del enfoque único de JS y encuentro extraño el carácter extraño en algunos de los anales más oscuros del lenguaje ;-) Sin embargo, una cosa que siempre me ha molestado es cómo administrar los eventos listos para documentos a medida que se hacen cada vez más grandes. a través del tiempo (y como resultado menos enfocado / específico a la página que se sirve)
El problema es que tenemos un archivo JS (fusionado y minificado, aunque es intrascendente para mis preguntas). La mayoría de los JS se escriben utilizando el patrón revelador del módulo, y jQuery es nuestro marco de referencia. Así que toda nuestra funcionalidad JS está lógicamente agrupada en métodos, espacio de nombres y, a continuación, justo en la parte inferior del archivo de comandos tenemos este
$(function(){
//lots of code here, usually calling encapsulated methods
//on our namespaced revealing module
});
El problema es que no todo el código en este manejador listo para documentos se refiere a cada página. Por ejemplo, en una página, solo el 10% podría ser relevante, en otra, quizás el 80% podría ser relevante. Para mí, esto se siente increíblemente mal, siento que solo debería ejecutar el código que necesito por página, principalmente para la eficiencia, pero también la capacidad de mantenimiento.
He buscado en Google enfoques para este problema, pero no puedo encontrar nada, ¡tal vez solo estoy buscando algo equivocado!
De todos modos, entonces mis preguntas son:
- ¿Alguien ha pensado alguna vez sobre este tema?
- ¿Es realmente un problema en la opinión de otras personas?
- ¿Tiene un manejador listo para documentos grande y completo en su código o está más enfocado para el tipo de página que se sirve?
- Si este último, ¿cómo se maneja esto? ¿Controladores múltiples que se conectan en JS o escupiendo dinámicamente el manejador de documentos preparados en el servidor?
Esperamos las opiniones de la gente sobre el asunto.
Aclamaciones
"El problema es que tenemos un archivo JS"
No estoy seguro de cómo puede evitarlo siempre que incluya el mismo archivo JS (fusionado) para todas las páginas. Podría usar alguna lógica del lado del servidor para combinar diferentes piezas para ir con diferentes páginas, pero luego probablemente perderá los beneficios del almacenamiento en memoria caché del JS del lado del cliente, entonces ...
Los proyectos en los que he trabajado (normalmente) han utilizado varios archivos JS, un par es común a todas las páginas y los otros están incluidos o no son apropiados, algunos archivos JS están incluidos en una sola página. Esto significa que prácticamente todas las páginas incluyen las funciones comunes de la biblioteca, ya sea que las utilicen o no, pero el archivo común JS se almacena en caché, por lo que no importa. El código específico de la página realmente es específico de la página.
No puedo decir por tu pregunta si eres consciente de ello, pero puedes tener múltiples manejadores de documentos listos (¿creo que jQuery los ejecuta en el orden en que estaban vinculados?). Entonces, si divide el archivo JS, cada archivo JS puede incluir su propio documento listo. Por supuesto, ese enfoque tiene sus propios gastos generales, pero creo que es mejor que poner todo en el mismo archivo.
Creo que la solución intuitiva a este problema es, simplemente, reducir la cantidad de trabajo realizado en el momento de la carga.
Si su código se ve algo así como:
$(function () {
// Binds a single click event (which will never be triggered if the hypothetical
// widget is never used), regardless of how many widgets are used on the page.
$(document).delegate(''.rating-widget'', ''click'', namespace.rating.handler);
// and so on for similar things which simply require event handler registration
// Initializes each of the forms on the page, letting the initializer take care
// of any details (datepicker widgets, validation, etc) based on the root element
$(''form.fancy'').each(namespace.fancyform.initializer);
// and so on for similar things that require initialization
// ... (for each type of thing on the page requiring initial setup,
// find the most general/high level pattern that sufficient)
});
las cosas deberían ser relativamente fáciles de mantener, incluso si hay unas pocas docenas de líneas. No hay una lógica complicada / interesante en este nivel para actualizar / recordar cuando se trabaja con el código del componente y, como todo en este nivel es trivial, es fácil de leer. En este punto, no hay necesidad de inventar algún sistema de registro complicado; no va a ser más simple que .delegate
y .each
.
Tenga en cuenta también que todo lo anterior maneja con gracia el caso donde el componente no se utiliza. En esos casos, se realiza poco o ningún trabajo y no es necesaria una lógica condicional.
Para ideas interesantes sobre cómo puede implementar los manipuladores / inicializadores, es posible que desee echar un vistazo, por ejemplo, a la charla " Contextual jQuery en la práctica " que Doug Neiner dio en jQuery Boston la semana pasada.
En primer lugar, si está utilizando jQuery, document.getElementsByTagName no es realmente necesario, simplemente puede usar $ ("nombre de la etiqueta"). Eche un vistazo a la documentación de jQuery Selectors para obtener aún más magia.
Su solución de trabajo en progreso es la forma en que lo haría, pero no es necesario que se tome la molestia de definir funciones adicionales, obtener clases de cuerpo, ejecutar un ciclo, o cualquier otro tipo de jazz ... ¿por qué no solo usar la función .hasClass() jQuery?
$(function() {
if($("body").hasClass("article")) {
alert("some article specific code");
}
if($("body").hasClass("landingPage")) {
alert("some landing specific code");
}
});
Bam. Todo lo que necesita. Si quieres ser aún más eficiente, puedes reutilizar una consulta corporal:
$(function() {
var body = $("body");
if(body.hasClass("article")) {
alert("some article specific code");
}
if(body.hasClass("landingPage")) {
alert("some landing specific code");
}
});
Aquí está en jsfiddle: http://jsfiddle.net/W8nx8/6/
Esto es lo que he hecho en mi proyecto rails mvc con javascript pesado, he creado un espacio de nombres separado para los controladores en js que se asemeja al controlador de rieles
class BusinessController
def new
end
def index
end
end
y
Var Business = {
init : function(action) {
//code common to the Business module
//even add the common jquery doc ready here, its clean
//and call the page specific action
this[action]();
},
new : function() {
// check jquery document ready code here, thats relevant to this action
//New rental page specific code here
},
index : function() {
// check jquery document ready code here, thats relevant to this action
//index rental page specific code here
}
}
y en el código de vista (lado del servidor) simplemente inicie el código js específico de la página
<script type="text/javascript">
<%= controller_name %>.init(''<%= controller.action_name %>'');
//which will render to
// Business.init(index);
</script>
Puedes ajustarlo bastante para que funcione en cualquier idioma. Y a este enfoque no le importa si tiene un solo archivo o varios archivos.
Gran pregunta De hecho, me encargo de esto mediante el uso de eventos de carga de página personalizados. Entonces, en mi archivo .js central, tengo una clase como la siguiente:
var Page = {
init: function(pageName) {
switch (pageName)
{
case: ''home'': {
// Run home page specific code
}
case: ''about'': {
// Run about page specific code
}
...
}
}
}
Puede llamar esto de varias maneras, ya sea en un $(document).ready()
específico de la página o desde el script central usando algún tipo de analizador de URL (literalmente todo es posible con un analizador de URL):
$(document).ready(function() {
// http://www.mydomain.com/about
var currentPage = window.location.pathname; // "about"
Page.init(currentPage);
});
window.location
Referencia de DOM: https://developer.mozilla.org/en/DOM/window.location
Me gusta el enfoque de RameshVel. También encontré la gema Paloma para crear JavaScript específico de la página. Por ejemplo:
Paloma.controller(''Admin/Users'', {
new: function(){
// Handle new admin user
}
});
Primero coloco clases específicas en el cuerpo o en contenedores específicos, por ejemplo, articles
, form-validation
, password-meter
, .... Si tengo una aplicación MVC, prefiero poner el nombre del controlador en una clase de cuerpo. Esto no duele demasiado y puede ser útil también para el estilo.
Luego, en cada bloque de document.ready compruebo la existencia de dicha clase, y si no existe, regreso de esta función. Este enfoque es más simple ya que no tiene el código principal dentro de una cláusula if. Este enfoque se asemeja a las afirmaciones que se utilizan para verificar los requisitos previos de una función.
Ejemplo:
$(function(){
if($(''body'').hasClass(''articles'') === false){ return; }
//body of the articles code
});
$(function(){
if($(''body'').hasClass(''password-meter'') === false){ return; }
//include password meter in page
});
La ventaja de este enfoque es que ningún código no deseado puede colarse en una devolución de llamada lista, lo que hace que sea más fácil de reutilizar. La desventaja es que obtienes muchos bloqueos de devolución de llamada y si no prestas atención, el código duplicado puede colarse fácilmente en tu aplicación.
Sé de dónde vienes. Right webapps para uso móvil puede parecer una tontería, lo que hace que el usuario descargue un archivo masivo de JS lleno de código irrelevante (¡la API de JQuery para uno es un mal comienzo!).
Lo que hago, que puede ser correcto o incorrecto, pero que parece funcionar, es incluir funciones requeridas página por página antes de la etiqueta. (Esta posición, en su mayor parte, soluciona el problema con el documento.) Sin embargo, no puede evitar sentir que este enfoque es demasiado simple.
Estoy interesado en escuchar otras respuestas, así que es una buena pregunta, +1.
Tener menos archivos javascript minimiza la cantidad de solicitudes enviadas al servidor y el almacenamiento en caché de los archivos hace que la segunda y la tercera página se carguen más rápido. Normalmente, pienso en la probabilidad de que algunas partes de un archivo js sean necesarias en las siguientes páginas (y no solo en la página actual). Esto me hace categorizar mi código js en dos tipos: código que va en mi "main.js", e incluso si no se usa, lo va a descargar el cliente (pero no necesariamente se lo ejecutará, explicaré), y el la segunda categoría de código va en archivos separados. En realidad, podría crear varios archivos agrupados por probabilidad. Esto depende de los detalles de su proyecto. Si se trata de un proyecto a gran escala, ejecutar algunos análisis estadísticos sobre el comportamiento del usuario podría revelar formas interesantes de agrupar el código js. Ahora que el código se ha descargado al cliente, no queremos ejecutarlo todo. Lo que debes hacer es tener diferentes diseños o páginas. Coloque un parcial en el diseño o página. Dentro del conjunto parcial, una variable de javascript. Recupere la variable javascript en el código javascript y determine si desea ejecutar algún código o no.
es decir:
Crea un "_stats.html.erb" parcial, coloca este código en él:
<script type="text/javascript">
var collect_statistics = <%= collect_statistics %>;
</script>
Coloque el parcial en las páginas en las que desea recopilar estadísticas: show.html.erb
<%= render "_stats", :collect_statistics => false %>
Ahora en su archivo js, haga lo siguiente:
$(document).load( function() {
if (typeof collect_statistics != "undefined" && collect_statistics) {
// place code here
}
});
¡Espero que esto ayude!