usuario para normas interfaces diseño colores dart dart-webui

dart - para - colores en el diseño de interfaces



¿Cómo construir una aplicación de interfaz de usuario compleja con múltiples vistas? (3)

Voy a construir una aplicación compleja con muchas vistas diferentes. Imagina por ejemplo la solución eshop. Puede haber muchas vistas diferentes:

  • Página de contacto con información estática.
  • Formulario de inscripción para nuevos clientes.
  • Vista de tu pedido
  • Listado de los productos
  • Detalles sobre un producto
  • ...

Ahora estoy un poco confundido, cómo crear una aplicación tan compleja utilizando la interfaz de usuario web. Me gustaría tener las plantillas HTML para las vistas separadas en varios archivos y con cierta lógica para determinar cuál se debe representar.

Supongamos que quiero tener una única plantilla maestra que contenga elementos básicos como encabezado y pie de página, luego tengo muchas plantillas de contenido, que deberían inyectarse en el lugar correcto dentro de la plantilla maestra.

Hasta ahora, siempre he visto solo pequeños ejemplos de plantillas de uso de la interfaz de usuario web de Dart, así que no tengo idea de cómo lograrlo.


Creé un elemento de polímero <bind-view> que crea y agrega un elemento de vista según la ruta actual. El elemento trabaja con el paquete route_hierarchical .
Ver BWU Polymer Routing en GitHub para más detalles.

Una configuración de ruta se parece a

library bwu_polymer_routing_example.route_initializer; import ''package:route_hierarchical/client.dart'' as rt; import ''package:bwu_polymer_routing/module.dart''; class RouteInitializer implements Function { void call(rt.Router router, RouteViewFactory views) { views.configure({ ''usersList'': routeCfg( path: ''/users'', view: ''user-list'', defaultRoute: true, dontLeaveOnParamChanges: true, enter: (route) => router.go(''usersList'', {})), ''user'': routeCfg( path: ''/user/:userId'', view: ''user-element'', dontLeaveOnParamChanges: true, mount: { ''articleList'': routeCfg( path: ''/articles'', view: ''article-list'', defaultRoute: true, dontLeaveOnParamChanges: true, mount: { ''article'': routeCfg( path: ''/article/:articleId'', view: ''article-element'', bindParameters: [''articleId'', ''userId''], dontLeaveOnParamChanges: true, mount: { ''view'': routeCfg( path: ''/view'', defaultRoute: true, dontLeaveOnParamChanges: true), ''edit'': routeCfg( path: ''/edit'', dontLeaveOnParamChanges: true) }) }) }) }); } }

<app-element> contiene el <app-element> <bind-view> , un marcador de posición donde se agrega la vista configurada para la ruta actual. Las vistas pueden ser anidadas. Cualquier vista puede contener un elemento <bind-view> . Esto permite crear una composición de vista jerárquica sin mucha repetición.

<!DOCTYPE html> <link rel=''import'' href=''../../../../packages/polymer/polymer.html''> <link rel=''import'' href=''../../../../packages/bwu_polymer_routing/bind_view.html''> <link rel=''import'' href=''user_list.html''> <link rel=''import'' href=''user_element.html''> <link rel=''import'' href=''article_list.html''> <link rel=''import'' href=''article_element.html''> <polymer-element name=''app-element''> <template> <bind-view id=''app-element''></bind-view> </template> <script type=''application/dart'' src=''app_element.dart''></script> </polymer-element>

El archivo app_element.dart contiene el código de inicialización del enrutador

class AppModule extends Module { AppModule() : super() { install(new RoutingModule(usePushState: true)); bindByKey(ROUTE_INITIALIZER_FN_KEY, toValue: new RouteInitializer()); } } @CustomTag(''app-element'') class AppElement extends PolymerElement with DiContext { AppElement.created() : super.created(); @override void attached() { super.attached(); initDiContext(this, new ModuleInjector([new AppModule()])); } }

El paquete también contiene algunos mixins de ayuda para agregar la funcionalidad de inyección de dependencias (DI) a los elementos de polímero, como el mixin DiContext usa aquí. La inyección de constructor no se puede usar con Polymer, pero los eventos son un buen sustituto.

El mixin DiConsumer permite solicitar una instancia de DI con este código simple

@CustomTag(''article-list'') class ArticleList extends PolymerElement with DiConsumer { @observable String userId; @override void attached() { super.attached(); // The two lines below show how to request instances from DI // but they are redundant here because // route parameters are assigned to attributes of the view automatically // when the view is created or when the values change var di = inject(this, [RouteProvider /* add more types here as needed */]); userId = (di[RouteProvider] as RouteProvider).parameters[''userId'']; } }


He reunido un pequeño ejemplo de cómo lo hago actualmente (espero que pronto veamos una aplicación de ejemplo de mejores prácticas para esto):

Para obtener el código fuente completo de este ejemplo, consulte gist: Cómo crear una aplicación de interfaz de usuario web con varias vistas en Dart

Aplicación principal

  • app.html : contiene el diseño principal de la aplicación, crea una instancia del componente de encabezado y pie de página y crea un contenedor para las vistas.
  • app.dart - Maneja los eventos de navegación y reemplaza la vista dentro del contenedor de vista (ver más abajo)
  • app.css

Componentes web

Encabezado y pié de página

  • header.html - Componente Web para el encabezado
  • footer.html - Componente web para pie de página

Puntos de vista

  • contact.html - Componente web para la vista de contactos
  • contact.dart - archivo de dardo que contiene la clase ContactsView
  • products.html - Componente web para la vista de productos
  • products.dart - archivo de dardo que contiene la clase ProductsView

Cambio entre vistas

La forma estándar de crear una instancia de los componentes web es mediante el uso de <x-foo></x-foo> en HTML . Como tenemos diferentes vistas, tendremos que crear una instancia de los Componentes Web dentro de nuestro código Dart . Haciendo esto tenemos que llamar manualmente los métodos del ciclo de vida de los componentes web. Esto no es sencillo y podría mejorarse en el futuro (consulte el Número 93, que también contiene algunos ejemplos).

Aquí es cómo puede cambiar las vistas (fuente de app.dart ):

import ''dart:html''; import ''package:web_ui/web_ui.dart''; import ''contact.dart''; import ''products.dart''; void main() { // Add view navigation event handlers query(''#show-contact-button'').onClick.listen(showContactView); query(''#show-products-button'').onClick.listen(showProductView); } // Used to call lifecycle methods on the current view ComponentItem lifecycleCaller; /// Switches to contacts view void showContactView(Event e) { removeCurrentView(); ContactView contactView = new ContactView() ..host = new Element.html(''<contact-view></contact-view>''); lifecycleCaller = new ComponentItem(contactView)..create(); query(''#view-container'').children.add(contactView.host); lifecycleCaller.insert(); } /// Switches to products view void showProductView(Event e) { removeCurrentView(); ProductsView productsView = new ProductsView() ..host = new Element.html(''<products-view></products-view>''); lifecycleCaller = new ComponentItem(productsView); lifecycleCaller.create(); query(''#view-container'').children.add(productsView.host); lifecycleCaller.insert(); } void removeCurrentView() { query(''#view-container'').children.clear(); if (lifecycleCaller != null) { // Call the lifecycle method in case the component needs to do some clean up lifecycleCaller.remove(); } }

Y aquí está la fuente para app.html :

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>A Complex Web UI Application</title> <link rel="stylesheet" href="app.css"> <!-- import the header and footer components --> <link rel="components" href="header.html"> <link rel="components" href="footer.html"> <!-- import the view components --> <link rel="components" href="contact.html"> <link rel="components" href="products.html"> </head> <body> <header-component></header-component> <div id="view-container"></div> <button id="show-contact-button">show contact view</button> <button id="show-products-button">show products view</button> <footer-component></footer-component> <script type="application/dart" src="app.dart"></script> <script src="packages/browser/dart.js"></script> </body> </html>

Nota : Tuve que importar los componentes de la vista a través de <link rel="components" href="contact.html"> a pesar de que no hago referencia directa en el archivo HTML.


Puede utilizar la biblioteca de route combinada con plantillas para automatizar en gran medida el proceso.

En urls.dart definirá las rutas que manejará la aplicación. app.dart configurará el escucha de ruta. Por último, app.html contendrá un contenedor de página que cambiará automáticamente el componente de la página (mediante el uso de la creación de instancias de plantilla).

Con esta estructura configurada, la navegación de la página se puede manejar a través de etiquetas de anclaje regulares en lugar de llamar a funciones personalizadas para cambiar la página.

Para agregar una nueva página tendrá que hacer lo siguiente:

  1. Agregar una nueva ruta en urls.dart
  2. Crear un nuevo componente web en las pages/ carpeta
  3. Agrega una nueva plantilla condicional para la página en app.html

A continuación puede ver un ejemplo de una aplicación que maneja una página de inicio y una página de contacto:

urls.dart:

library urls; import ''package:route/url_pattern.dart''; final homeUrl = new UrlPattern(r''/''); final contactUrl = new UrlPattern(r''/contact'');

app.dart:

import ''dart:html''; import ''package:web_ui/web_ui.dart''; import ''package:route/client.dart''; import ''urls.dart'' as urls; import ''package:web_ui/watcher.dart'' as watchers; // Setup the routes to listen to void main() { var router = new Router() ..addHandler(urls.homeUrl, showPage) ..addHandler(urls.contactUrl, showPage) ..listen(); } // Change the page that we are on void showPage(String path) { watchers.dispatch(); }

app.html

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sample app</title> <link rel="stylesheet" href="app.css"> <!-- import the pages --> <link rel="components" href="pages/xhomepage.html"> <link rel="components" href="pages/xcontactpage.html"> </head> <body> <!-- You could put a header here if you want !--> <!-- Templates take care of automatically switching the page !--> <div class="pages"> <template instantiate="if urls.homeUrl.matches(window.location.pathname)"> <x-home-page></x-home-page> </template> <template instantiate="if urls.contactUrl.matches(window.location.pathname)"> <x-contact-page></x-contact-page> </template> </div> <!-- You could put a footer here if you want !--> <script type="application/dart" src="app.dart"></script> <script src="packages/browser/dart.js"></script> </body> </html>

Edición: he eliminado el paso donde app.dart tiene que definir sus propias páginas. En su lugar, las plantillas verifican si la ruta de la URL coincide con el UrlPattern definido en urls.dart. Esto debería simplificar un poco más las cosas.