Tour of Heroes应用程序有新的要求:javascript
完成后,用户将能够像这样浏览应用程序:css
为了知足这些要求,您将添加Angular路由器到应用程序。html
有关路由器的更多信息,请阅读路由和导航页面。java
当你完成这个页面,应用程序应该看起来像这个实例(查看源代码)。git
在继续英雄之旅以前,请确认您具备如下结构。github
若是该应用程序还没有运行,请启动该应用程序。 在进行更改时,请经过从新加载浏览器窗口来保持运行。web
计划以下:json
路由是导航的另外一个名称。 路由是导航从视图到视图的机制。bootstrap
当前的应用程序加载AppComponent并当即显示英雄列表。 修改后的应用程序应该提供一个可选的视图(Dashboard和Heroes),而后默认为其中的一个。api
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从服务器检索到的数据替换模拟数据。