2009-10-16 16 views
9

Necesito buenos ejemplos y mejores prácticas en la arquitectura del programa.¿Cómo organizar una interfaz de usuario de Javascript?

Estoy tratando de construir una interfaz de usuario JS para una aplicación que funciona con Google.Maps. En el primer borrador, el usuario debería ser capaz de dibujar formas geométricas en el mapa de una manera similar a G.M. Luego, las formas se envían a través de AJAX y se muestra la respuesta.

El problema es que el código se complicó solo con la edición de polígonos.

Inspirado por el "Programador de cinta de ductos" de Joel, traté de esbozar un código sencillo que realice acciones e intercambie controladores de eventos, para evitar grandes árboles de if-else. El botón "Nuevo poli" crea un observador para map.onclick, cambia los manejadores de eventos para otros botones u los oculta, y se oculta, etc.

El inconveniente de este enfoque es que el código de manejo de datos se mezcla con la interfaz. Un código que crea un contenedor div para mostrar los datos en el nuevo polígono se encuentra junto al código que trata con G.M o w/los datos de forma. Si quiero revisar la UI, tendré que procesar la aplicación WHOLE.

Podría revisarlo más tarde y mover este código de generación de IU en otro lugar, pero luego vino mi programador principal. Por el contrario, insistió en el enfoque de "mensajes": un sistema simple de eventos donde los objetos se suscriben a los eventos y los activan. El código de interfaz puede aislarse perfectamente del manejo de datos y hablar con G.M, pero ahora cada oyente debe verificar si este mensaje es correcto.

Por ejemplo, al hacer clic en una poli en un mapa debe resaltarlo y comenzar a editarlo. Pero no si se está dibujando otro poli. Entonces, algún código de "¿estás hablando?" Es necesario en todas partes.

Agradeceré los buenos ejemplos de enfoques de arquitectura de IU.

Respuesta

5

La idea de manejo de eventos sugerida es un buen enfoque.

Aquí hay algunas ideas más:

  • Hacer lo dibujo forma un componente
  • La forma de dibujo componente envía eventos a otro código, para reaccionar a cosas como "edición" o "clic"
  • Este componente también podría manejar la parte de edición - Envía evento "hecho clic" al controlador, los controladores le dicen al componente entrar en modo de edición
  • Mientras estaba en modo de edición, el componente no enviaba eventos normales "chasqueados" hasta que se cerraba la edición, evitando su problema de tener que verificar

En general, es una buena idea tener una capa de "vista" que simplemente se ocupe de mostrar los datos y enviar eventos sobre las acciones del usuario en esos datos (es decir. clics, etc.) a una capa de "controlador", que luego decide qué hacer, por ejemplo, podría decidir cambiar la vista al modo de edición.

0

recomendaría tener pocas variables de objeto que contengan el estado (0, dibujo, edición, ... cualquier otro requerido) - esto lo ayudaría a decidir si permite el manejo de eventos o simplemente lo entierra si, por ejemplo, el dibujo está hecho y haciendo clic en polygone editable sucede.

en cuanto a la IU - No estoy seguro de si su pregunta está dirigida a usted - desarrollando el script o al usuario, ya que está mezclando dos cosas aquí.

tenga en cuenta que para un usuario todo debe ser lo más simple posible: si está editando, no le permita dibujar. si está dibujando, no le permita editar (puede haber superposición de polígonos). sin embargo, ¿permite al usuario cambiar rápidamente de la edición (por ejemplo, hacer clic derecho?) al dibujo, o en otras palabras, cancelar el estado actual.

1

En pocas palabras, el paradigma de editor-suscriptor funciona bien para hacer formas geométricas. Primero crea una línea de comandos cuya primitiva es el editor de polígono base que publica. El objeto Canvas parece obvio aquí para pintar, el método habitual repaint() para actualizar la vista del cliente (programación eventdriven normalmente en C puede revisar, por ejemplo, gráficos opengl o glut eventdriven), combinado con la API gmap regular que también uso, publisher-subscriber patrón o fábrica son buenos patrones de diseño cualquiera que sea la implementación de gráficos. algo complicado es la latitud y la longitud en la matriz entre json y capa de persistencia, todavía no hay geocodificación inversa en el servidor, nombrar es algo inconsistente y para multilingua las aplicaciones cambian el lenguaje humano relativo del usuario y se duplican (París en Texto, París en Francia ...) ,. Mira si te gusta mi aplicación va, registra los nombres geográficos y de usuario en relación coordinada espacial con geoıp worldwide

function wAdd(response){ 
map.clearOverlays(); 
if(!response||response.Status.code!=200){ 

} 
else{ 
    try{ 
     place=response.Placemark[0]; 
     point=new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]); 
     marker=new GMarker(point); 
     map.addOverlay(marker); 
     marker.openInfoWindowHtml('<a href="/li?lat='+place.Point.coordinates[1]+'&lon='+place.Point.coordinates[0]+'&cc='+place.AddressDetails.Country.CountryNameCode+'">'+place.AddressDetails.Country.AdministrativeArea.Locality.LocalityName+'<span id="wr2"></span> '+ nads(place.Point.coordinates[1],place.Point.coordinates[0])+' ' +'<img src="http://geoip.wtanaka.com/flag/'+place.AddressDetails.Country.CountryNameCode.toLowerCase()+'.gif">'); 
    } 
    catch(e){ 
     try{ 
      place=response.Placemark[0]; 
      point=new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]); 
      marker=new GMarker(point); 
      map.addOverlay(marker); 
      marker.openInfoWindowHtml('<a href="/li?lat='+place.Point.coordinates[1]+'&lon='+place.Point.coordinates[0]+'&cc='+place.AddressDetails.Country.CountryNameCode+'">'+place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName+'<span id="wr2"></span> '+ nads(place.Point.coordinates[1],place.Point.coordinates[0])+' ' +'<img src="http://geoip.wtanaka.com/flag/'+place.AddressDetails.Country.CountryNameCode.toLowerCase()+'.gif">'); 
     } 
     catch(e){ 
try { 
     place=response.Placemark[0]; 
       point=new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]); 
       marker=new GMarker(point); 
       map.addOverlay(marker); 
       marker.openInfoWindowHtml('<a href="/li?lat='+place.Point.coordinates[1]+'&lon='+place.Point.coordinates[0]+'&cc='+place.AddressDetails.Country.CountryNameCode+'">'+place.AddressDetails.Country.CountryName+'<span id="wr2"></span> '+ nads(place.Point.coordinates[1],place.Point.coordinates[0])+' ' +'<img src="http://geoip.wtanaka.com/flag/'+place.AddressDetails.Country.CountryNameCode.toLowerCase()+'.gif">'); 
      } 
    catch(e){ 
place=response.Placemark[0]; 
     marker=new GMarker(point); 
       map.addOverlay(marker); 
marker.openInfoWindowHtml('<a href="/li">'+place.address+'</a>'); 
} 

     } } 
    }map.addOverlay(geoXml); 
} 
5

No sé si esto no viene al caso. Pero uso esto como un templo para todos mis proyectos de javascript.

(function() { 
var window = this, 
    $ = jQuery, 
    controller, 
    view, 
    model; 

controller = { 
    addEventForMenu : function() { 
     // Add event function for menu 
    } 
}; 

view = { 
    content : { 
     doStuff : function() { 

     } 
    }, 

    menu : { 
     openMenuItem : function() { 

     } 
    } 
}; 

model = { 
    data : { 
     makeJson : function() { 
      // make json of string 
     }, 

     doAjax : function() { 

     }, 

     handleResponse : function() { 

     } 
    } 
} 

$.extend(true, $.view, view); 
})(); 

Lo bueno aquí es que es sólo el objeto vista que se extiende a la DOM, el resto se mantiene dentro del alcance anónimo.

También en proyectos de errores i crear en estos archivos para cada parte, es decir, map.js, content.js, editor.js

Si sólo importa la denominación de sus métodos en el objeto vista puede tener tantos archivos como desee durante el desarrollo. Cuando el proyecto se establece en un entorno de producción, solo lo hago un archivo y lo minimizo.

..fredrik

0

La primera cosa que hacer es crear un servicio que se ajusta sobre la API de Google. Esto es para que luego, si necesita cambiar los servicios de mapas (mapas de Windows o mapas de yahoo). Entonces puedes poner una fachada sobre el google service. A continuación, puede colocar algunas envolturas sobre su servicio y dividirlas en una vista (salida) y modelo (entrada) y administrar esto con controladores/presentadores. Verifique en Model View Controller/Model View Presenter/Presenter First/Humble Dialog en Wikipedia. Debe discutir la separación que estás buscando. También la página web de Martin Fowler entra en patrones de presentación. Deberías revisar mi antiguo blog ugly-lisp-code. Tengo referencias a mensajes dirigidos por eventos/eventos.

Si tiene un pub/sub de uno a uno, simplemente almacene un controlador de eventos (cierre/lambda/función de primer orden) en el objeto que va a desencadenar el evento.

Si tiene un pub/sub de uno a muchos, necesitará un objeto más complejo para almacenar sus cierres.

¡LOL! En este momento he estado viendo este mismo problema exacto. Voy a escribir sobre el uso de un presentador primero en JavaScript on my blog. A simple comienzo huesos en presenter y model.

[edit] es posible que desee comprobar esto stackoverflow question. Una de las respuestas tiene un enlace para separar preocupaciones en MVC. El enlace está en A List Apart.

Cuestiones relacionadas