Tour of Heroes应用程序有新的要求:
完成后,用户将可以像这样浏览应用程序:
为了满足这些要求,您将添加Angular路由器到应用程序。
有关路由器的更多信息,请阅读路由和导航页面。
当你完成这个页面,应用程序应该看起来像这个实例(查看源代码)。
在继续英雄之旅之前,请确认您具有以下结构。
如果该应用程序尚未运行,请启动该应用程序。 在进行更改时,请通过重新加载浏览器窗口来保持运行。
计划如下:
路由是导航的另一个名称。 路由是导航从视图到视图的机制。
当前的应用程序加载AppComponent并立即显示英雄列表。 修改后的应用程序应该提供一个可选的视图(Dashboard和Heroes),然后默认为其中的一个。
AppComponent只应该处理导航,所以你可以将Heroes的显示从AppComponent移出并放到它自己的HeroesComponent中。
AppComponent已经专注于英雄。 将代码移出AppComponent,将其重命名为HeroesComponent,并创建一个单独的AppComponent外壳。
请执行下列操作:
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是应用程序外壳。 它将在顶部有一些导航链接,下面有一个显示区域。
执行这些步骤:
第一稿看起来是这样的: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';
}
刷新浏览器。 该应用程序仍然运行并显示英雄。
应该在用户点击按钮后显示英雄而不是自动显示。 换句话说,用户应该能够导航到英雄列表。
使用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_PROVIDERS:web/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),
]);
}
使用哪个位置策略 默认的LocationStrategy是PathLocationStrategy,所以在生产中,可以使用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对象:
在路由和导航页面阅读更多关于定义路由的信息。
如果您访问localhost:8080/#/heroes,路由器应该匹配英雄路线的URL并显示一个HeroesComponent。 但是,您必须告诉路由器在哪里显示组件。 为此,在模板的末尾添加一个<router-outlet>元素。 RouterOutlet是ROUTER_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 {}
稍后您将使这个组件更加有用。
添加一个类似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 导航链接,在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之间导航。
为了让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。
之前,您从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也使用这种逻辑:
在这个仪表板中你指定了四个英雄(第二,第三,第四和第五)。
刷新浏览器以查看新仪表板中的四个英雄名称。
虽然所选英雄的详细信息显示在HeroesComponent的底部,但用户应该能够通过以下其他方式导航到HeroDetailComponent:
您可以在AppComponent中添加到HeroDetailComponent的路由,其中定义了其他路由。
新的路由是不寻常的,你必须告诉HeroDetailComponent显示哪个英雄。 您不必告诉HeroesComponent或DashboardComponent任何东西。
目前,父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现在的样子: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';
将RouteParams,HeroService和Location服务注入到构造函数中,并将其值保存在私有字段中: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是一个数字。 路由参数始终是字符串。 所以路由参数值被转换成一个数字。
在ngOnInit()中,你使用了HeroService还没有的getHero()方法。 要解决这个问题,打开HeroService,并添加一个getHero()方法,通过id从getHeroes()过滤英雄列表。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中,当前的模板展示了一个“主/细节”风格,顶部是英雄列表,下方是选定的英雄的详细信息。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。 相反,您将在自己的页面上显示英雄细节,并按照您在仪表板中所做的方式路由到它。 进行这些更改:
当用户从列表中选择一个英雄时,他们不会进入详细页面。 相反,他们会在此页面上看到一个迷你细节,并且必须单击一个按钮才能导航到完整的详细信息页面。
在模板底部添加以下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导航到HeroesDetailComponent。 按钮的点击事件绑定到一个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文件。
在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">
现在看看应用程序。 仪表板,英雄和导航链接的样式。
查看此页面的实例(查看源代码)中的示例源代码。 确认您具有以下结构:
以下是您在此页面中所取得的成果:
前方的路 你有很多基础,你需要建立一个应用程序。 您仍然缺少一个关键部分:远程数据访问。
在下一页中,您将使用http从服务器检索到的数据替换模拟数据。