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從服務器檢索到的數據替換模擬數據。

下一節

相關文章
相關標籤/搜索