AngularDart4.0 英雄之旅-教程-07路由

Tour of Heroes应用程序有新的要求:javascript

  • 添加一个Dashboard视图。
  • 添加在HeroesDashboard视图之间导航的功能。
  • 当用户在任一视图中点击英雄名称时,导航至所选英雄的详细视图。
  • 当用户点击电子邮件中的深层连接时,打开特定英雄的详细视图。

完成后,用户将能够像这样浏览应用程序:css

为了知足这些要求,您将添加Angular路由器到应用程序。html

有关路由器的更多信息,请阅读路由和导航页面。java

 当你完成这个页面,应用程序应该看起来像这个实例(查看源代码)。git

开始阶段

在继续英雄之旅以前,请确认您具备如下结构。github

若是该应用程序还没有运行,请启动该应用程序。 在进行更改时,请经过从新加载浏览器窗口来保持运行。web

行动计划

计划以下:json

  • AppComponent转换为仅处理导航的应用程序外壳程序。
  • 将当前AppComponent中的英雄相关的从新定位到单独的HeroesComponent
  • 添加路由。
  • 建立一个新的DashboardComponent
  • Dashboard绑定到导航结构中。

路由是导航的另外一个名称。 路由是导航从视图到视图的机制。bootstrap

分割AppComponent

当前的应用程序加载AppComponent并当即显示英雄列表。 修改后的应用程序应该提供一个可选的视图(DashboardHeroes),而后默认为其中的一个。api

AppComponent只应该处理导航,因此你能够将Heroes的显示从AppComponent移出并放到它本身的HeroesComponent中。

 

HeroesComponent

AppComponent已经专一于英雄。 将代码移出AppComponent,将其重命名为HeroesComponent,并建立一个单独的AppComponent外壳。

请执行下列操做:

  • 重命名并将app_component.*文件移动到src / heroes_component.*
  • 从导入路径中删除src /前缀。
  • AppComponent类重命名为HeroesComponent(仅在本地重命名,仅在此文件中)。
  • 将选择器my-app重命名为my-heroes
  • 将模板URL更改成heroes_component.html,并将样式文件更改成heroes_component.css

lib/src/heroes_component.dart (showing renamings only) 

@Component(
  selector: 'my-heroes',
  templateUrl: 'heroes_component.html',
  styleUrls: const ['heroes_component.css'],
)
class HeroesComponent implements OnInit {
  HeroesComponent(
      this._heroService,
      );
}

建立AppComponent

新的AppComponent是应用程序外壳。 它将在顶部有一些导航连接,下面有一个显示区域。

执行这些步骤:

  • 建立文件lib / app_component.dart
  • 定义一个AppComponent类。
  • 使用my-app选择器在类的上方添加@Component注解。
  • 将如下英雄组件移到AppComponent
  •      title类属性。
  •      @Component 模板<h1>节点,其中包含对title的绑定。
  • HeroesComponent添加到AppComponent的指令列表中,以便Angular识别<my-heroes>标签。
  • HeroService添加到AppComponentproviders 列表中,由于在其余全部视图中都须要它。
  • 从升级后的HeroesComponent providers列表中删除HeroService
  • AppComponent添加支持导入语句。

第一稿看起来是这样的:lib/app_component.dart

import 'package:angular/angular.dart';

import 'src/hero_service.dart';
import 'src/heroes_component.dart';

@Component(
  selector: 'my-app',
  template: '''
    <h1>{{title}}</h1>
    <my-heroes></my-heroes>
  ''',
  directives: const [HeroesComponent],
  providers: const [HeroService],
)
class AppComponent {
  final title = 'Tour of Heroes';
}

刷新浏览器。 该应用程序仍然运行并显示英雄。

添加路由

应该在用户点击按钮后显示英雄而不是自动显示。 换句话说,用户应该可以导航到英雄列表。

更新pubspec

使用Angular路由(angular_router)启用导航。 因为路由器在本身的包中,首先将该包添加到应用的pubspec

并不是全部的应用程序都须要路由,这就是为何Angular路由器处于独立的可选软件包中的缘由。

导入库

Angular路由器是多个服务(ROUTER_PROVIDERS)、指令(ROUTER_DIRECTIVES)和配置类的组合。 你能够经过导入路由库来获得它们:lib/app_component.dart (router import)

import 'package:angular_router/angular_router.dart';

使路由器可用

要告诉Angular您的应用使用路由,请在应用的引导程序功能中指定ROUTER_PROVIDERSweb/main.dart

import 'package:angular/angular.dart';
import 'package:angular_router/angular_router.dart';
import 'package:angular_tour_of_heroes/app_component.dart';

void main() {
  bootstrap(AppComponent, [
    ROUTER_PROVIDERS,
    // Remove next line in production
    provide(LocationStrategy, useClass: HashLocationStrategy),
  ]);
}

使用哪一个位置策略
默认的LocationStrategyPathLocationStrategy,因此在生产中,可使用ROUTER_PROVIDERS,而没必要使用LocationStrategy提供程序。 在开发过程当中,使用HashLocationStrategy更方便,由于pub serve不支持deep linking。 有关详细信息,请参阅位置策略的LocationStrategy and browser URL styles

接下来,将ROUTER_DIRECTIVES添加到@Component注解中,并删除HeroesComponent: 

lib/app_component.dart (directives)

directives: const [ROUTER_DIRECTIVES],

您能够从指令列表中移除HeroesComponent,由于AppComponent不会直接显示英雄; 这是路由器的工做。 很快你会从模板中删除<my-heroes>

<base href>

打开index.html并确保在<head>部分的顶部有一个<base href =“...”>元素(或者一个动态设置这个元素的脚本)。

正如在“Routing and Navigation”页面的“ Set the base href”部分所述,示例应用程序使用如下脚本:

web/index.html (base-href)

<head>
  <script>
    // WARNING: DO NOT set the <base href> like this in production!
    // Details: https://webdev.dartlang.org/angular/guide/router
    (function () {
      var m = document.location.pathname.match(/^(\/[-\w]+)+\/web($|\/)/);
      document.write('<base href="' + (m ? m[0] : '/') + '" />');
    }());
  </script>

配置路由

Routes 告诉路由当用户点击一个连接或者将一个URL粘贴到浏览器地址栏中时显示哪些视图。

建立一个路由配置(RouteConfig)来保存应用程序路由定义的列表。 定义第一个路由做为到英雄组件的路由。lib/app_component.dart (Heroes route)

@RouteConfig(const [
  const Route(path: '/heroes', name: 'Heroes', component: HeroesComponent)
])

路由定义是一个具备如下命名参数的Route对象:

  • path:路由器将此字符串与浏览器地址栏(/ heroes)中的URL匹配。
  • name:路线名称(Heroes)。 它必须以大写字母开头以免与路径混淆。
  • component(组件):此路由导航时到(HeroesComponent)时将被激活的组件。

路由和导航页面阅读更多关于定义路由的信息。

Router outlet

若是您访问localhost:8080/#/heroes,路由器应该匹配英雄路线的URL并显示一个HeroesComponent。 可是,您必须告诉路由器在哪里显示组件。
为此,在模板的末尾添加一个<router-outlet>元素。 RouterOutletROUTER_DIRECTIVES之一。 当用户经过应用程序导航时,路由器会在<router-outlet>正下方显示每一个组件。
刷新浏览器,而后访问localhost:8080 /#/ heroes。 你应该看到英雄列表。

路由连接

用户没必要粘贴路由路径到地址栏。 相反,向模板添加一个锚点,点击后会触发到HeroesComponent的导航。

修改后的模板以下所示:lib/app_component.dart (template)

template: '''
  <h1>{{title}}</h1>
  <a [routerLink]="['Heroes']">Heroes</a>
  <router-outlet></router-outlet>
''',

 请注意锚标记中的[routerLink]绑定。 RouterLink指令告诉路由在用户点击连接时的位置。

您使用连接参数列表定义了一个路由指令, 这个列表在咱们的小样本中只有一个元素,引用的路由名称。 回头看看路由配置,肯定“Heroes”是到HeroesComponent的路由的名字。

了解路由章节中的连接参数列表。

刷新浏览器,浏览器显示应用标题和英雄连接,但不是英雄列表。点击英雄导航连接。地址栏更新为 /#/heroes(或同等/#heroes),英雄列表显示。

AppComponent如今看起来像这样:lib/app_component.dart

import 'package:angular/angular.dart';
import 'package:angular_router/angular_router.dart';

import 'src/hero_service.dart';
import 'src/heroes_component.dart';

@Component(
  selector: 'my-app',
  template: '''
    <h1>{{title}}</h1>
    <a [routerLink]="['Heroes']">Heroes</a>
    <router-outlet></router-outlet>
  ''',
  directives: const [ROUTER_DIRECTIVES],
  providers: const [HeroService],
)
@RouteConfig(const [
  const Route(path: '/heroes', name: 'Heroes', component: HeroesComponent)
])
class AppComponent {
  final title = 'Tour of Heroes';
}

 AppComponent有一个路由,并显示路由视图。 为此,为了区别于其余类型的组件,这种组件类型称为路由组件。

添加一个仪表板

只有当多个视图存在时,路由才有意义。 要添加另外一个视图,请建立一个占位DashboardComponent

lib/src/dashboard_component.dart (v1)

import 'package:angular/angular.dart';

@Component(
  selector: 'my-dashboard',
  template: '<h3>My Dashboard</h3>',
)
class DashboardComponent {}

稍后您将使这个组件更加有用。

配置dashboard 路由

添加一个相似Heroes路由的dashboard 路由:lib/app_component.dart (Dashboard route)

const Route(
  path: '/dashboard',
  name: 'Dashboard',
  component: DashboardComponent,
),

添加一个重定向路由

目前,浏览器在/在地址栏中启动。 当应用程序启动时,它应该显示仪表板,并在地址栏中显示路径 /#/dashboard 。

要作到这一点,请添加剧定向路由:lib/app_component.dart (Redirect route)

const Redirect(path: '/', redirectTo: const ['Dashboard']),

或者,您能够将dashboard 定义为默认路由。 在路由和导航页面阅读有关默认路由和重定向的更多信息。

将导航添加到dashboard 

在模板上添加dashboard 导航连接,在heroes连接上方。lib/app_component.dart (template)

template: '''
  <h1>{{title}}</h1>
  <nav>
    <a [routerLink]="['Dashboard']">Dashboard</a>
    <a [routerLink]="['Heroes']">Heroes</a>
  </nav>
  <router-outlet></router-outlet>
''',

<nav>标签目前尚未作任何事情,可是当您格式化连接时,它们会颇有用。

在浏览器中,转至应用程序根目录(/)并从新加载。 该应用程序显示dashboard ,您能够在dashboard heroes之间导航。 

将heroes添加到dashboard 

为了让dashboard 更有趣,您一眼就能够看到前四名的英雄。

template元数据替换为指向新模板文件的templateUrl属性,并添加以下所示的指令(还要添加必要的导入):lib/src/dashboard_component.dart (metadata)

@Component(
  selector: 'my-dashboard',
  templateUrl: 'dashboard_component.html',
  directives: const [CORE_DIRECTIVES, ROUTER_DIRECTIVES],
)

templateUrl的值能够是这个包或其余包中的asset。 要在另外一个包中使用资源,请使用完整的包引用,如“package:some_other_package / dashboard_component.html”。

使用如下内容建立模板文件:lib/src/dashboard_component.html

<h3>Top Heroes</h3>
<div class="grid grid-pad">
  <div *ngFor="let hero of heroes">
    <div class="module hero">
      <h4>{{hero.name}}</h4>
    </div>
  </div>
</div>

* ngFor再次用于遍历英雄列表并显示他们的名字。 额外的<div>元素将有助于之后的格式化样式。

共享HeroService

要填充组件的英雄列表,您能够从新使用HeroService

以前,您从HeroesComponent的提供程序列表中删除了HeroService,并将其添加到AppComponent的提供程序列表中。 这个举动建立了一个单例HeroService实例,可用于应用程序的全部组件。 Angular注入HeroService,您能够在DashboardComponent中使用它。

获取英雄

dashboard_component.dart中,添加如下导入语句。lib/src/dashboard_component.dart (imports)

import 'dart:async';

import 'package:angular/angular.dart';
import 'package:angular_router/angular_router.dart';

import 'hero.dart';
import 'hero_service.dart';

如今建立DashboardComponent类,以下所示:lib/src/dashboard_component.dart (class)

class DashboardComponent implements OnInit {
  List<Hero> heroes;

  final HeroService _heroService;

  DashboardComponent(this._heroService);

  Future<Null> ngOnInit() async {
    heroes = (await _heroService.getHeroes()).skip(1).take(4).toList();
  }
}

HeroesComponent也使用这种逻辑:

  • 定义一个英雄列表属性。
  • 在构造函数中注入HeroService,并将其保存在一个专用的_heroService字段中。
  • 调用服务来获取Angular ngOnInit()生命周期钩子中的英雄。

在这个仪表板中你指定了四个英雄(第二,第三,第四和第五)。

刷新浏览器以查看新仪表板中的四个英雄名称。

导航到英雄的细节

虽然所选英雄的详细信息显示在HeroesComponent的底部,但用户应该可以经过如下其余方式导航到HeroDetailComponent

  • 从仪表板到选定的英雄。
  • 从英雄名单到选定的英雄。
  • 从“深层连接”网址粘贴到浏览器地址栏中。

路由到英雄细节

您能够在AppComponent中添加到HeroDetailComponent的路由,其中定义了其余路由。

新的路由是不寻常的,你必须告诉HeroDetailComponent显示哪一个英雄。 您没必要告诉HeroesComponentDashboardComponent任何东西。

目前,父HeroesComponent使用以下绑定将组件的hero属性设置为hero对象:

<hero-detail [hero]="selectedHero"></hero-detail>

可是这种绑定在任何路由脚本中都不起做用。

参数化的路由

您能够将英雄的id添加到路由路径。 当路由到英雄的id为11,你能够指望看到这样的路径:

/detail/11

 / detail /部分是不变的。 尾随的数字id在英雄与英雄间变换。 您须要使用表明英雄id的参数来表示路由的可变部分。

添加一个附带参数的路由

首先,导入英雄细节组件:

import 'src/hero_detail_component.dart';

接下来,添加如下路由:lib / app_component.dart(HeroDetail route)

const Route(
  path: '/detail/:id',
  name: 'HeroDetail',
  component: HeroDetailComponent,
),

路径中的冒号(:)表示:id在导航到HeroDetailComponent时是特定英雄id的占位符。

你已经完成了应用程序的路由。

您没有向模板添加英雄详情连接,由于用户单击导航连接不是为了查看特定的英雄; 而是点击一个英雄的名字,无论名字是显示在仪表板仍是英雄列表中。 可是,直到HeroDetailComponent被修改并准备好导航到这个时候,它才会起做用。

修改HeroDetailComponent

如下是HeroDetailComponent如今的样子:lib/src/hero_detail_component.dart (current)

import 'package:angular/angular.dart';
import 'package:angular_forms/angular_forms.dart';
import 'hero.dart';
@Component(
  selector: 'hero-detail',
  template: '''
    <div *ngIf="hero != null">
      <h2>{{hero.name}} details!</h2>
      <div><label>id: </label>{{hero.id}}</div>
      <div>
        <label>name: </label>
        <input [(ngModel)]="hero.name" placeholder="name"/>
      </div>
    </div>
  ''',
  directives: const [CORE_DIRECTIVES, formDirectives],
)
class HeroDetailComponent {
  @Input()
  Hero hero;
}

该模板不会改变。 英雄的名字将显示相同的方式。 主要的变化是如何获得英雄的名字。

您将再也不接收父组件属性绑定中的英雄,所以您能够从hero字段中删除@Input()注解:lib/src/hero_detail_component.dart (hero with @Input removed)

class HeroDetailComponent implements OnInit {
  Hero hero;
}

新的HeroDetailComponent将从路由器的RouteParams服务中获取id参数,并使用HeroService来获取具备该id的英雄。

添加如下导入:lib/src/hero_detail_component.dart (added-imports)

import 'dart:async';

import 'package:angular_router/angular_router.dart';

import 'hero_service.dart';

RouteParamsHeroServiceLocation服务注入到构造函数中,并将其值保存在私有字段中:lib/src/hero_detail_component.dart (constructor)

final HeroService _heroService;
final RouteParams _routeParams;
final Location _location;

HeroDetailComponent(this._heroService, this._routeParams, this._location);

告诉类实现OnInit接口。

class HeroDetailComponent implements OnInit {

ngOnInit()生命周期的钩子中,从RouteParams服务中提取id参数值,并使用HeroService来获取具备该id的英雄。lib/src/hero_detail_component.dart (ngOnInit)

Future<Null> ngOnInit() async {
  var _id = _routeParams.get('id');
  var id = int.parse(_id ?? '', onError: (_) => null);
  if (id != null) hero = await (_heroService.getHero(id));
}

注意如何经过调用RouteParams.get()方法来提取id

英雄id是一个数字。 路由参数始终是字符串。 因此路由参数值被转换成一个数字。

添加HeroService.getHero()

ngOnInit()中,你使用了HeroService尚未的getHero()方法。 要解决这个问题,打开HeroService,并添加一个getHero()方法,经过idgetHeroes()过滤英雄列表。lib/src/hero_service.dart (getHero)

Future<Hero> getHero(int id) async =>
    (await getHeroes()).firstWhere((hero) => hero.id == id);

找回路

用户有几种方式导航到HeroDetailComponent

要在其余地方导航,用户能够单击AppComponent中的两个连接之一,或单击浏览器的后退按钮。 如今添加第三个选项,一个goBack()方法,使用您以前注入的Location服务在浏览器的历史堆栈中向后导航一步。

lib/src/hero_detail_component.dart (goBack)

void goBack() => _location.back();

回头太远可能会把用户带出应用程序。 在一个真正的应用程序中,您可使用routerCanDeactivate()挂钩来防止此问题。 在CanDeactivate页面上阅读更多信息。

 您将使用绑定到后退按钮的事件链接此方法,您将添加到组件模板。

<button (click)="goBack()">Back</button>

将模板迁移到名为hero_detail_component.html的文件:lib/src/hero_detail_component.html

<div *ngIf="hero != null">
  <h2>{{hero.name}} details!</h2>
  <div>
    <label>id: </label>{{hero.id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="hero.name" placeholder="name" />
  </div>
  <button (click)="goBack()">Back</button>
</div>

更新组件templateUrl元数据指向您刚刚建立的模板文件。lib/src/hero_detail_component.dart (metadata)

@Component(
  selector: 'hero-detail',
  templateUrl: 'hero_detail_component.html',
  directives: const [CORE_DIRECTIVES, formDirectives],
)

刷新浏览器并访问localhost:8080/#details/11. 应该显示英雄11的详细信息。 在仪表板或英雄列表中选择英雄不起做用。 你会接下来的处理。

选择一个仪表板英雄

当用户选择仪表板中的英雄时,应用程序应该导航到HeroDetailComponent以容许用户查看和编辑选择的英雄。

仪表板英雄的行为应该像锚标签:当悬停在英雄的名字,目标网址应该显示在浏览器的状态栏,用户应该可以复制连接或在新标签打开英雄详细信息视图。

为了达到这个效果,打开dashboard_component.html并用一个锚点替换<div * ngFor ...>元素(子元素保持不变):lib/src/dashboard_component.html (repeated <a> tag)

<a *ngFor="let hero of heroes" [routerLink]="['HeroDetail', {id: hero.id.toString()}]" class="col-1-4">
  <div class="module hero">
    <h4>{{hero.name}}</h4>
  </div>
</a>

注意[routerLink]绑定。 如本页“路由连接”部分所述,AppComponent模板中的顶级导航将路由器连接设置为目标路由,/dashboard / heroes的固定名称。

此次,您绑定到包含连接参数列表的表达式。 该列表包含两个元素:目标路由的名称和设置为当前英雄id值的路由参数。

这两个列表项与您以前添加的参数化英雄细节路由定义中的名称和:id相对应:lib/app_component.dart (HeroDetail route)

const Route(
  path: '/detail/:id',
  name: 'HeroDetail',
  component: HeroDetailComponent,
),

刷新浏览器并从仪表板中选择一个英雄; 该应用程序导航到该英雄的细节。

在HeroesComponent中选择一个英雄

HeroesComponent中,当前的模板展现了一个“主/细节”风格,顶部是英雄列表,下方是选定的英雄的详细信息。lib/src/heroes_component.html

<h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes"
      [class.selected]="hero === selectedHero"
      (click)="onSelect(hero)">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>
<hero-detail [hero]="selectedHero"></hero-detail>

你不会再在这里显示完整的HeroDetailComponent。 相反,您将在本身的页面上显示英雄细节,并按照您在仪表板中所作的方式路由到它。 进行这些更改:

  • 从模板的最后一行删除<hero-detail>元素。
  • 从指令列表中删除HeroDetailComponent
  • 删除英雄细节导入。

当用户从列表中选择一个英雄时,他们不会进入详细页面。 相反,他们会在此页面上看到一个迷你细节,而且必须单击一个按钮才能导航到完整的详细信息页面。

添加迷你细节

在模板底部添加如下HTML片断,在<hero-detail>以前的地方:lib/src/heroes_component.html (mini detail)

<div *ngIf="selectedHero != null">
  <h2>
    {{selectedHero.name | uppercase}} is my hero
  </h2>
  <button (click)="gotoDetail()">View Details</button>
</div>

点击一个英雄(但不要如今尝试,由于它不会工做),用户应该在英雄列表下面看到这样的东西:

因为管道运算符(|)以后的插值绑定中包含的uppercase管道,英雄的名称将以大写字母显示。

{{selectedHero.name | uppercase}} is my hero

管道是格式化字符串,货币金额,日期和其余显示数据的好方法。 有几个管道是已提供的,你能够写你本身的。

警告在模板中使用Angular管道以前,须要将其列在组件的@Component注解的pipes参数中。 您能够单独添加管道,或者为了方便起见,可使用COMMON_PIPES组。lib/src/heroes_component.dart (pipes)

@Component(
  selector: 'my-heroes',
  pipes: const [COMMON_PIPES],
)

在“Pipes”页面上阅读有关管道的更多信息。

刷新浏览器。 从英雄列表中选择英雄将激活迷你细节视图。 查看详细信息按钮不起做用。

更新HeroesComponent类

响应按钮单击,HeroesComponent导航到HeroesDetailComponent。 按钮的点击事件绑定到一个gotoDetail()方法,该方法应该经过告诉路由器去哪里命令性地导航。

这种方法须要对组件类进行如下更改:

  • 导入angular_router
  • 在构造函数中注入路由器,以及HeroService
  • 经过调用路由器的navigate()方法来实现gotoDetail()

这里是修改后的HeroesComponent类:lib/src/heroes_component.dart (class)

class HeroesComponent implements OnInit {
  final HeroService _heroService;
  final Router _router;
  List<Hero> heroes;
  Hero selectedHero;

  HeroesComponent(
      this._heroService,
      this._router
      );

  Future<Null> getHeroes() async {
    heroes = await _heroService.getHeroes();
  }

  void ngOnInit() => getHeroes();

  void onSelect(Hero hero) => selectedHero = hero;

  Future<Null> gotoDetail() => _router.navigate([
        'HeroDetail',
        {'id': selectedHero.id.toString()}
      ]);
}

gotoDetail()中,你正在向路由器的navigate()方法传递一个两元素连接参数列表(一个名字和路由参数),就像你在DashboardComponent中的[routerLink]绑定中同样。

刷新浏览器并开始点击。 用户能够在应用程序周围进行导航,从仪表板到英雄详细信息,而后返回,从英雄列表到英雄详细信息,再次回到英雄。

你已经达到推进这个页面的全部导航要求。

风格化应用程序

该应用程序是功能,但它须要样式。 仪表板英雄应显示在一排矩形。 为此目的,您已经收到了大约60行CSS,包括一些简单的媒体查询响应式设计。

正如您如今所知,将CSS添加到组件样式元数据将会隐藏组件逻辑。 相反,您将添加CSS来分隔.css文件。

Dashboard 样式

lib / src文件夹中建立一个dashboard_component.css文件,并在组件元数据的styleUrls列表属性中引用该文件,以下所示:

lib / src/dashboard_component.dart(styleUrls)

@Component(
  selector: 'my-dashboard',
  templateUrl: 'dashboard_component.html',
  styleUrls: const ['dashboard_component.css'],
  directives: const [CORE_DIRECTIVES, ROUTER_DIRECTIVES],
)

lib / src/dashboard_component.css

[class*='col-'] {
  float: left;
  text-decoration: none;
  padding-right: 20px;
  padding-bottom: 20px;
}
[class*='col-']:last-of-type {
  padding-right: 0;
}
*, *:after, *:before {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;
}
h3 {
  text-align: center; margin-bottom: 0;
}
h4 {
  position: relative;
}
.grid {
  margin: 0;
}
.col-1-4 {
  width: 25%;
}
.module {
	padding: 20px;
	text-align: center;
	color: #eee;
	max-height: 120px;
	min-width: 120px;
	background-color: #607D8B;
	border-radius: 2px;
}
.module:hover {
  background-color: #EEE;
  cursor: pointer;
  color: #607d8b;
}
.grid-pad {
  padding: 10px 0;
}
.grid-pad > [class*='col-']:last-of-type {
  padding-right: 20px;
}
@media (max-width: 600px) {
	.module {
	  font-size: 10px;
	  max-height: 75px; }
}
@media (max-width: 1024px) {
	.grid {
	  margin: 0;
	}
	.module {
	  min-width: 60px;
	}
}

英雄细节风格

lib / src文件夹中建立一个hero_detail_component.css文件,并在组件元数据的styleUrls列表中引用该文件:

lib / src/hero_detail_component.dart(styleUrls)

@Component(
  selector: 'hero-detail',
  templateUrl: 'hero_detail_component.html',
  styleUrls: const ['hero_detail_component.css'],
  directives: const [CORE_DIRECTIVES, formDirectives],
)

lib / src/hero_detail_component.css

label {
  display: inline-block;
  width: 3em;
  margin: .5em 0;
  color: #607D8B;
  font-weight: bold;
}
input {
  height: 2em;
  font-size: 1em;
  padding-left: .4em;
}
button {
  margin-top: 20px;
  font-family: Arial;
  background-color: #eee;
  border: none;
  padding: 5px 10px;
  border-radius: 4px;
  cursor: pointer; cursor: hand;
}
button:hover {
  background-color: #cfd8dc;
}
button:disabled {
  background-color: #eee;
  color: #ccc;
  cursor: auto;
}

设置导航连接样式

lib文件夹中建立一个app_component.css文件,并在组件元数据的styleUrls列表中引用该文件:

lib / app_component.dart(styleUrls)

styleUrls: const ['app_component.css'],

lib / app_component.css

h1 {
  font-size: 1.2em;
  color: #999;
  margin-bottom: 0;
}
h2 {
  font-size: 2em;
  margin-top: 0;
  padding-top: 0;
}
nav a {
  padding: 5px 10px;
  text-decoration: none;
  margin-top: 10px;
  display: inline-block;
  background-color: #eee;
  border-radius: 4px;
}
nav a:visited, a:link {
  color: #607D8B;
}
nav a:hover {
  color: #039be5;
  background-color: #CFD8DC;
}
nav a.router-link-active {
  color: #039be5;
}

提供的CSS使AppComponent中的导航连接更像可选按钮。 早些时候,你用<nav>元素包围了这些连接:

router-link-active 类

Angular路由器将router-link-active类添加到其路由与活动路由相匹配的HTML导航元素。 你所要作的就是定义它的风格。

应用程序全局样式

将样式添加到组件时,能够将组件须要的全部内容(HTML,CSS和代码)一块儿放在一个方便的位置。 把它打包起来很容易,在其余地方从新使用组件。

您还能够在任何组件以外的应用程序级别建立样式。

设计师提供了一些基本样式来应用于整个应用程序的元素。 这些对应于您在安装期间先前安装的全套主样式。 这是一个摘录:web/styles.css (excerpt)

@import url(https://fonts.googleapis.com/css?family=Roboto);
@import url(https://fonts.googleapis.com/css?family=Material+Icons);

/* Master Styles */
h1 {
  color: #369;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 250%;
}
h2, h3 {
  color: #444;
  font-family: Arial, Helvetica, sans-serif;
  font-weight: lighter;
}
body {
  margin: 2em;
}
body, input[text], button {
  color: #888;
  font-family: Cambria, Georgia;
}
/* ··· */
/* everywhere else */
* {
  font-family: Arial, Helvetica, sans-serif;
}

若有必要,建立文件web / styles.css。 确保文件包含此处提供的主要样式。 另外编辑web / index.html来引用这个样式表。

web / index.html(link ref)

<link rel="stylesheet" href="styles.css">

如今看看应用程序。 仪表板,英雄和导航连接的样式。

应用程序结构和代码

查看此页面的实例(查看源代码)中的示例源代码。 确认您具备如下结构:

你走过的路

如下是您在此页面中所取得的成果:

  • 您添加了Angular路由器来浏览不一样的组件。
  • 您了解了如何建立路由器连接来表示导航菜单项。
  • 您使用路由器连接参数导航到用户选择的英雄的细节。
  • 您在多个组件之间共享HeroService
  • 您添加了uppercase管道来格式化数据。

你的应用应该看起来像这个实例(查看源代码)。

前方的路
你有不少基础,你须要创建一个应用程序。 您仍然缺乏一个关键部分:远程数据访问。

在下一页中,您将使用http从服务器检索到的数据替换模拟数据。

下一节

相关文章
相关标签/搜索