路由
Posted wpengch1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了路由相关的知识,希望对你有一定的参考价值。
注:学习使用,禁止转载
在web开发中,路由说的是根据浏览器上的URL的规则,将应用程序分成不同的区域。
比如我们访问一个网站的/路径,我们可能访问的是这个网站的home目录,如果我们访问/about,我们可能访问的是“about page”等等。
为什么要路由
在我们的应用程序中定义路由是有用的,因为我们能:
- 将应用程序分离成不同的区域
- 在应用程序中维护状态
- 根据特定的规则保护应用程序的区域
比如,假设我们编写一个inventory的app,它跟我们在前面描述的有点像。
当我们第一次访问时,我们可能会看到一个可以输入字符的输入框,并且获得一个匹配该字符的产品列表。
之后,我们可能想要去点击一个给定的产品去访问它的详细信息。
因为我们的程序是客户端的,所以技术上不要求我们修改页面的时候改变URL。但是值得思考一下:所有的页面都使用相同的URL后果是什么:
- 你不能在刷新页面的时候保存你在app中的位置
- 你不能去制定书签页,稍后返回来
- 你不能和其他人分享这个页面的URL
或者直接说,就是路由让我们定义一个URL字符串,这个URL字符串制定了我们在app中的哪个部分。
在我们的inventory app中,我们可以为每一个activity指定一系列不同的路由,比如:
首页由http://our-app/.代表,当我们访问这个的时候,我们会被重定向到home页面:http://our-app/home。
当访问‘About US’的时候,URL可能会变成”http://our-app/about“,如果我们发送http://our-app/about给其他人,其他人会跟我们一样看到相同的页面。
client-side路由是怎么工作的
以前,我们可能编写过服务器端的路由(虽然没有必要完成这个)。通常服务器端路由的工作是,当HTTP请求进来后,服务器会根据请求进来的URL分配一个不同的Controller。
比如,使用express你可能会写下面这样的代码:
var express = require('express');
var router = express.Router();
// define the about route
router.get('/about', function(req, res)
res.send('About us');
);
或者使用Ruby on Rails你可能会像这样写:
# routes.rb
get '/about', to: 'pages#about'
# PagesController.rb
class PagesController < ActionController::Base
def about
render
end
end
每个框架各不相同,但是大致情况都是,你有一个服务器,它接收一个请求,然后使用路由控制器根据请求的URL路由到一个特定的Controller,在Controller里面根据路径和参数运行一个特定的行动。
客户端路由概念上是非常类似的。只是实现不同。使用客户端路由,每次URL改变时,我们不必都向服务器发送请求,angular2的app我们称为SPA(单页面应用程序,Single Page Application),因为服务器仅仅给了我们一个简单的页面,渲染不同的页面是javascript做的工作。
所以,在我们的Javascript中,怎么实现路由呢?
开始的时候:使用锚标记(anchor tag)
客户端路由有一个黑客(hack)的方式开始:不是使用页面的形式,而是使用锚标记。
你可能已经知道,锚标记就是让你在页面内直接连接到某一个地方,当你点击的时候,浏览器会滚动到定义锚的地方。
比如,我们在一个html页面定义一个锚标记。
<!-- ... lots of page content here ... -->
<a name="about"><h1>About</h1></a>
然后我们访问http://something/#about,浏览器会直接跳转到定义了about锚标记的H1标签那里。
客户端框架的一个聪明做法是利用锚标记,通过格式化它们作为路径,在我们的app中代表路由。
比如,SPA里面的about路由,它可能会像http://something/#/about,这个被叫着基于hash的路由(hash-based routing)
这个技巧的明晰的是,它看起来像一个正常的URL,因为他使用一个锚标记的开始。
进化:HTML5客户端路由
通过引入HTML5,浏览器获得了创建和更改显示URL的能力,而不需要一个新的请求。
这个是通过history.pushState函数完成的,它向Javascript暴露了浏览器的导航历史。
所以现在,不需要依靠锚标记,而是依靠pushState去执行无需重新加载的历史操作。
:fa-info-circle: 这种route方式在angular1中就已经有了,不过需要使用$locationProvider.html5Mode(true)激活它们。
然而,在angular2中,html是默认的方式,在这章的后面,我们会讲解这样将html模式修改为旧的锚标记的模式。
:fa-info-circle: 当时用HTML模式时,有两个事情需要注意
- 不是所有的浏览器都支持HTML5模式,如果你需要兼容旧的浏览器,你需要使用锚标记的方式
- 服务器必须支持HTML5的路由。
对于服务器必须支持HTML5路由可能是不明晰的,在这章的后面我们会详细讨论。
编写我们的第一个路由
在angular中,配置路由是通过映射路径到处理它们的组件那里。
让我们创建一个具有多个路由的app,在我们的app中有三个路由:
- 一个主页面路由,使用/#/home路径
- 一个关于页面,使用/#/about路径
- 一个联系我们页面,使用/#/contact路径
并且,当我们访问首页的时候,会重定向到home路径。
angular2的组件路由
注意:
知道编写这版的时候(May 5th, 2016, rc.1),rout怎么发生一些变化,下面标志了/@router-deprecated的代码,这些事来自beta17的。
我们会尽快更新组件路由这章。在那之前,许多概念都是相同的。
在angular2中,配置组件路由有三个主要的部分:
- RouteConfig注解描述我们的app支持的路由
- RouterOutlet是一个组件占位符,它扩展每个路由的内容
- RouterLink使用去链接路由
让我详细看看
RouteConfig
为了定义app的路由,我们使用RouteConfig配置我们的组件。
code/routes/basic/app/ts/app.ts
@RouteConfig([
path: '/', name: 'root', redirectTo: ['/Home'] ,
path: '/home', name: 'Home', component: HomeComponent ,
path: '/about', name: 'About', component: AboutComponent ,
path: '/contact', name: 'Contact', component: ContactComponent ,
path: '/contactus', name: 'ContactUs', redirectTo: ['/Contact'] ,
])
关于这个组件注意下面这个事情:
- path标识了路由的URL
- name唯一标识当前路由,在RouteLink,redirectTo或者Route API中使用
- component将当前路由与一个组件绑定
- redirectTo用于将指定路径重定向到一个存在的路径
总的来说,路由的目标是指定那个组件处理那个路径
Redirections:重定向
当我们在路由定义上使用redirectTo,它告诉路由器,当我们访问这个路径的时候,我们想要重定向到另外一个路径。
在上面的代码中,如果我们访问http://localhost:8080/#/的根路径,会被重定向到默认的路由home。
另外一个联系我们的例子:
path: '/contactus', name: 'ContactUs', redirectTo: ['/Contact'] ,
在这个例子中,如果我们访问http://localhost:8080/#/contactus,我们会看到浏览器重定向到/contact
RouterOutlet
我们的@View有一个模板,它标识了一些div结构,作为导航的部分。和一个叫着router-outlet的指令
当我们改变路由的时候,我们想要去保持我们的模板,仅仅只修改里面的一部分。
在angular中,为了描述我们想要在哪里绘制路由的内容,我们使用RouterOutlet指令去标识
router-outlet预示路由组件在哪里渲染。
为了使用它,我们需要声明ROUTER_DIRECTIVES作为我们组件的directives,然后在html中增加一个标签
code/routes/basic/app/ts/app.ts
@Component(
selector: 'router-app',
directives: [ROUTER_DIRECTIVES],
template: `
<div>
<nav>
<a>Navigation:</a>
<ul>
<li><a [routerLink]="['/Home']">Home</a></li>
<li><a [routerLink]="['/About']">About</a></li>
<li><a [routerLink]="['/Contact']">Contact us</a></li>
</ul>
</nav>
<router-outlet></router-outlet>
</div>
`
)
如果你仔细看了上面的代码,你会发现在最后添加了一个router-outlet,当我们访问/home的时候,这里将会渲染HomeComponent。其他的组件也是一样。
RouterLink
现在我们知道在哪里渲染模板,那我们怎么告诉angular去导航到特定的路由呢?
我们可能试着直接在html建立链接:
<a href="/#/home">Home</a>
但是,如果我们这样做,当我们点击的时候,会发现页面重新加载了。在SPA中,这个永远不是我们需要的。
为了解决这个问题,angular2提供了一个解决方案,它可以让我们连接到特定的路由,但是让页面不重新加载:RouterLink指令。
code/routes/basic/app/ts/app.ts
<ul>
<li><a [routerLink]="['/Home']">Home</a></li>
<li><a [routerLink]="['/About']">About</a></li>
<li><a [routerLink]="['/Contact']">Contact us</a></li>
</ul>
我们可以看到,在a标签里面使用了[routerLink]。右边,我们有一个数组,”[‘/Home’]” or “[‘/About’]”,它指定我们点击的时候跳转到指定的路由页面。
它可能有点奇怪,它的值是一个字符数组,这是因为当我们点击我们可以做更多的事情,详细信息见自路由一节。
现在,我们仅仅使用route name。
所有东西放在一起
所以,现在,我们每一个部分都有了,就是将他们组合起来。
第一件事情就是编写index.html。下面是所有的代码:
code/routes/basic/app/index.html
<!doctype html>
<html>
<head>
<base href="/">
<title>ng-book 2: Angular 2 Router</title>
% for (var css in o.htmlWebpackPlugin.files.css) %
<link href="%=o.htmlWebpackPlugin.files.css[css] %" rel="stylesheet">
% %
</head>
<body>
<router-app></router-app>
<script src="/core.js"></script>
<script src="/vendor.js"></script>
<script src="/bundle.js"></script>
</body>
</html>
除了这条线,下面的代码应该很熟悉了
<base href="/">
这条线定义了一个基本的HTML标签,这个是用来告诉浏览器,在哪里查找图像和其他资源。
原来,angular路由器也依靠这个来构建它的路由信息。
比如,如果我们有一个/path路径的路由,并且有一个base定义,href=”/app”,完整的路径会混合起来。
有时,angular程序员不会去访问HTML的头部。比如,在一个大型应用程序中,重用头部和脚部的时候。
幸运的是,对于这个事情,有一个解决方案。当启动应用程序的时候,你可以以编程方式定义基础路径。
bootstrap(RoutesDemoApp, [
ROUTER_PROVIDERS,
provide(APP_BASE_HREF, useValue: '/')
]);
注入provide(APP_BASE_HREF, useValue: ‘/’),等同于使用base=‘/’。
创建组件
在讲解主页面之前,让我们为每一个路由创建一个组件。
HomeComponent
HomeComponent只有一个H1标签,它显示Welcome。
code/routes/basic/app/ts/components/HomeComponent.ts
/*
* Angular
*/
import Component from '@angular/core';
@Component(
selector: 'home',
template: `<h1>Welcome!</h1>`
)
export class HomeComponent
AboutComponent
同理,AboutComponent也仅仅只有一个h1
code/routes/basic/app/ts/components/AboutComponent.ts
/*
* Angular
*/
import Component from '@angular/core';
@Component(
selector: 'about',
template: `<h1>About</h1>`
)
export class AboutComponent
ContactComponent
跟aboutComponent一样。
code/routes/basic/app/ts/components/ContactComponent.ts
/*
* Angular
*/
import Component from '@angular/core';
@Component(
selector: 'contact',
template: `<h1>Contact Us</h1>`
)
export class ContactComponent
Application component
现在我们创建一个根组件,将这些组件组合起来。
开始导入需要的指令
code/routes/basic/app/ts/app.ts
import provide, Component from '@angular/core';
import bootstrap from '@angular/platform-browser-dynamic';
import
ROUTER_DIRECTIVES,
ROUTER_PROVIDERS,
RouteConfig,
from '@angular/router-deprecated';
import LocationStrategy, HashLocationStrategy from '@angular/common';
接下来,导入我们上面创建的组件
code/routes/basic/app/ts/app.ts
/*
* Components
*/
import HomeComponent from 'components/HomeComponent';
import AboutComponent from 'components/AboutComponent';
import ContactComponent from 'components/ContactComponent';
现在,让我们看看真正的组件代码
code/routes/basic/app/ts/app.ts
@Component(
selector: 'router-app',
directives: [ROUTER_DIRECTIVES],
template: `
<div>
<nav>
<a>Navigation:</a>
<ul>
<li><a [routerLink]="['/Home']">Home</a></li>
<li><a [routerLink]="['/About']">About</a></li>
<li><a [routerLink]="['/Contact']">Contact us</a></li>
</ul>
</nav>
<router-outlet></router-outlet>
</div>
`
)
在这个组件中,我使用两个路由指令:RouterOutlet和RouterLink。
这些指令和其他的通用路由组件定义在 ROUTER_DIRECTIVES中,当我们导入directive时,我们基本上导入了路由相关的所有指令。
回顾一下,RouterOutlet指令预示在哪里渲染我们的路由内容,使用戴白哦。
RouterLink只用来创建一个链接。
code/routes/basic/app/ts/app.ts
<li><a [routerLink]="['/Home']">Home</a></li>
<li><a [routerLink]="['/About']">About</a></li>
<li><a [routerLink]="['/Contact']">Contact us</a></li>
这将会使得angular获得点击事情的权利并根据路由定义导航到特定页面。
接下来,我们使用RouteConfig定义所有的路由
code/routes/basic/app/ts/app.ts
@RouteConfig([
path: '/', name: 'root', redirectTo: ['/Home'] ,
path: '/home', name: 'Home', component: HomeComponent ,
path: '/about', name: 'About', component: AboutComponent ,
path: '/contact', name: 'Contact', component: ContactComponent ,
path: '/contactus', name: 'ContactUs', redirectTo: ['/Contact'] ,
])
最后,我们定义RoutesDemoApp
code/routes/basic/app/ts/app.ts
class RoutesDemoApp
在app.ts的最后,我们启动应用程序。
code/routes/basic/app/ts/app.ts
bootstrap(RoutesDemoApp, [
ROUTER_PROVIDERS,
provide(LocationStrategy, useClass: HashLocationStrategy)
]);
上面的代码,不同的地方就是提供了bootstrap的第二个参数,第二个参数是需要注入我们应用程序的一个可注入的数组。
我们需要注入的第一个是ROUTER_PROVIDERS常量,这个常量是所有route 类的数组,像RouteRegistry和Location,它是必须的,对于route的工作来说。
第二个看起来更加复杂
provide(LocationStrategy, useClass: HashLocationStrategy)
让我们深入讲解着第二个参数
路由策略(route strategies)
angular去解析和创建来自路由定义的方式叫路由策略(location strategy)
:fa-info-circle:在angular1中叫路由模式(routing mode)
模式的策略是PathLocationStrategy,它使用的是HTML5路由。当使用这个策略的时候,路由是通过正规路径表示,像/home或者/contact
我们可以改变路由策略,通过将LocationStrategy绑定到一个新的策略,或者直接重新创建一个策略。
代替使用默认的PathLocationStrategy,我们也可以使用HashLocationStrategy.
我们默认使用hash strategy的愿意是因为如果我们使用HTML5策略,我们的路径是正规的。
这种方式,当我们点击一个链接然后跳转的时候,让我们看看从/about到/contact。
如果我们刷新页面,不是像服务器请求跟目录,而是请求的是/about或者/contact,但是,服务器不知道该路径,会返回一个404页面回来。
hash strategy的策略是基于锚标记的,像/#/home 或者 /#/contact,并且,服务器会理解/标签,后面的不用管,这样就能拿到正确的资源(这也是angular1默认使用这个策略的原因)。
:fa-info-circle:让我们看看怎么使用HTML5的模式
为了使用HTML路由模式,你必须配置所有的未知路径到根路径,在routes/basic项目中,我们包含了一个使用webpack-dev-server开发的脚本,它允许使用HTML5的模式。
为了使用它, cd routes/basic 并且运行 node html5-dev-server.js
最后,为了让我们的app使用这个新的策略,我们必须导入LocationStrategy和HashLocationStrategy:
code/routes/basic/app/ts/app.ts
import provide, Component from '@angular/core';
import bootstrap from '@angular/platform-browser-dynamic';
import
ROUTER_DIRECTIVES,
ROUTER_PROVIDERS,
RouteConfig,
from '@angular/router-deprecated';
import LocationStrategy, HashLocationStrategy from '@angular/common';
然后,直接加了引用给bootstrap
code/routes/basic/app/ts/app.ts
bootstrap(RoutesDemoApp, [
ROUTER_PROVIDERS,
provide(LocationStrategy, useClass: HashLocationStrategy)
]);
:fa-info-circle:如果你想要编写你自己的策略,只需要继承LocationStrategy,并且实现它的接口就可以了。一个好的学习方式就是去阅读HashLocationStrategy和PathLocationStrategy的源码。
Path location strategy
在我们的实例文件夹下,你会发现app/ts/app.html5.ts文件,如果你想要使用默认的路由策略,你只需要拷贝这个文件的内容到app.ts里面就可以了。
运行应用程序
你现在可以进入应用程序根目录(code/routes),并且运行npm run server去启动应用程序。
注意,浏览器的URL已经重定向到了#/home下面。
点击about。
路由参数(route parameter)
在我们的app中,我们通常希望导航到一个特定的资源,比如,我们有一个许多文章的网站,每篇文章有一个id。如果我们有文章的ID,我们可以导航到文章的详情页面,通过下面的URL:
/articles/3
或者ID为4的文章:
/articles/4
等等
很显然,我们不希望对每一个文章都写路由,我们希望使用一个变量或者叫路由参数去标注,我们可以在路由后面加一个冒号,后面添加参数,像这样:
/route/:param
在我们的新闻网站上,我们可能希望这样标注:
/articles/:id
为了增加参数到路由配置上,我们像下面这样写:
code/routes/music/app/ts/app.ts
@RouteConfig([
path: '/', name: 'root', redirectTo: ['Search'] ,
path: '/search', name: 'Search', component: SearchComponent ,
path: '/artists/:id', name: 'Artists', component: ArtistComponent ,
path: '/tracks/:id', name: 'Tracks', component: TrackComponent ,
path: '/albums/:id', name: 'Albums', component: AlbumComponent ,
])
当我们访问/artist/123的时候,123将作为参数传递进路由里面去。但是我们怎么去获取这个路由参数呢,
RouteParams
为了使用路由参数,我们首先需要导入RouteParams:
import RouteParams from "@angular/router-deprecated";
然后,将RouteParams注入构造器,让我们看看,有一个路由并且标识在下面:
@RouteConfig([
path: "/articles/:id", name: "articles", component: ArticleComponent
])
然后,我们编写ArticleComponent,我们增加RouteParams作为组件构造器的参数。
export class ArticleComponent
id: string;
constructor(private routeParams: RouteParams)
this.id = routeParams.get("id");
然后我们传递/articles/230,我们的组件ID属性会接收到230。
Music Search App
让我们编写一个更复杂的应用程序,我们构建一个音乐搜索程序,它有下面这些特征:
- 查找更定的音乐
- 在一个grid中显示搜索结果
- 显示歌手的详细信息
- 显示专辑的详细信息
- 显示音乐的详细信息,当点击音乐名字的时候,用户可以去播放
这个app会使用下面的路由:
- /search: 搜索表单和结果
- /artists/:id:歌手详细信息
- /albums/:id:专辑详细信息
- /tracks/:id:歌曲详细信息
第一步
第一件事情就是app.ts,看看它的导入:
code/routes/music/app/ts/app.ts
/*
* Angular
*/
import
Component,
provide
from '@angular/core';
import bootstrap from '@angular/platform-browser-dynamic';
import HTTP_PROVIDERS from '@angular/http';
import
ROUTER_DIRECTIVES,
ROUTER_PROVIDERS,
ROUTER_PRIMARY_COMPONENT,
Router,
RouteConfig,
from '@angular/router-deprecated';
import LocationStrategy, HashLocationStrategy, APP_BASE_HREF from '@angular/common';
然后,我们考虑组件怎么使用每一个路由:
- 对于Search路由,我们创建一个SearchComponent.,这个组件会告诉Spotify API去执行搜索操作,并且显示结果
- 对于Albums路由,我们会创建一个AlbumComponent,它会显示album的歌曲列表
- 对于Tracks路由,我们会创建TrackComponent,它会显示歌曲并且显示歌曲预览
现在,这个组件将于Spotify API进行交互,它看起来需要新建一个服务,然后使用http模块与之交互
让我们首先构建SpotifyService。
SpotifyService
我们将要实现的第一个方法就是searchByTrack,它会通过给定的字符搜索歌曲,具体参照Spotify API的搜索文档,这个节点定义了我们需要的东西:需要一个请求和一个type参数。
下面是第一版:
class SpotifyService
constructor(public http:Http)
searchByTrack(query:string)
let params:string = [
`q=$query`,
`type=track`
].join("&");
let queryURL:
`https://api.spotify.com/v1/search?$params`;
return this.http.request(queryURL).map(res => res.json());
这个函数对https://api.spotify.com/v1/search执行一个GET请求,传递我们的search参数和type参数。
所有调用searchByQuery函数的需要订阅Obsevable API,像下面这样:
service
.searchTrack('query')
.subscribe((res: any) => console.log('Got object', res))
SearchComponent
既然我们有了搜索歌曲的服务,接下来我们可以编写我们的组件了:
code/routes/music/app/ts/components/SearchComponent.ts
import Component, OnInit from '@angular/core';
import CORE_DIRECTIVES from '@angular/common';
import
Router,
RouterLink,
RouteParams,
from '@angular/router-deprecated';
/*
* Services
*/
import SpotifyService from 'services/SpotifyService';
这里,我们导入通用的内容,然后注入我们刚创建的SpotifyService。
code/routes/music/app/ts/components/SearchComponent.ts
@Component(
selector: 'search',
directives: [RouterLink, CORE_DIRECTIVES],
template: `
<h1>Search</h1>
<p>
<input type="text" #newquery
[value]="query"
(keydown.enter)="submit(newquery.value)">
<button (click)="submit(newquery.value)">Search</button>
</p>
<div *ngIf="results">
<div *ngIf="!results.length">
No tracks were found with the term ' query '
</div>
<div *ngIf="results.length">
<h1>Results</h1>
<div class="row">
<div class="col-sm-6 col-md-4" *ngFor="let t of results">
<div class="thumbnail">
<div class="content">
<img src=" t.album.images[0].url " class="img-responsive">
<div class="caption">
<h3>
<a [routerLink]="['/Artists', id: t.artists[0].id]">
t.artists[0].name
</a>
</h3>
<br>
<p>
<a [routerLink]="['/Tracks', id: t.id]">
t.name
</a>
</p>
</div>
<div class="attribution">
<h4>
<a [routerLink]="['/Albums', id: t.album.id]">
t.album.name
</a>
</h4>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`
)
然后,我们的目标就是像下面这样渲染歌曲:
搜索字段
让我们分解模板,第一部分就是一个搜索域。
code/routes/music/app/ts/components/SearchComponent.ts
<p>
<input type="text" #newquery
[value]="query"
(keydown.enter)="submit(newquery.value)">
<button (click)="submit(newquery.value)">Search</button>
</p>
这里,我们有一个输入框,并且绑定它的值到我们组件的query属性。我们也给这个input一个模板变量名字:#newquery.,我们在组件中使用newquery.value访问input的值。
这个button将会出发组件的submit函数,将input的值作为参数传递进去。
当敲击enter的时候,submit也会被触发。
搜索结果和链接
接下来就是显示结果,我们可以使用ngFor去迭代每一个result对象
code/routes/music/app/ts/components/SearchComponent.ts
<div class="row">
<div class="col-sm-6 col-md-4" *ngFor="let t of results">
对于每一个歌曲,我们显示歌手名字:
code/routes/music/app/ts/components/SearchComponent.ts
<h3>
<a [routerLink]="['/Artists', id: t.artists[0].id]">
t.artists[0].name
注意,我们使用RouterLink去定向[‘/artists’, id: t.artists[0].id].
这就是我们设置给定route的参数的方式,下面你会看到id这个值在一个合适的组件中被处理。
然后显示歌曲:
code/routes/music/app/ts/components/SearchComponent.ts
<p>
<a [routerLink]="['/Tracks', id: t.id]">
t.name
以及专辑
code/routes/music/app/ts/components/SearchComponent.ts
<h4>
<a [routerLink]="['/Albums', id: t.album.id]">
t.album.name
SearchComponent类
让我们看看它的构造函数
code/routes/music/app/ts/components/SearchComponent.ts
export class SearchComponent implements OnInit
query: string;
results: Object;
constructor(public spotify: SpotifyService, public router: Router,
public routeParams: RouteParams)
这里定义了两个属性:
- query:代表当前输入
- results:代表搜索结果
构造器中注入了SpotifyService、Router和RouteParams。
search
为了执行搜索操作,我们定义了search函数
code/routes/music/app/ts/components/SearchComponent.ts
search(): void
this.query = this.routeParams.get('query');
if (!this.query)
return;
this.spotify
.searchTrack(this.query)
.subscribe((res: any) => this.renderResults(res));
我们希望获取query参数,如果参数是空的不进行搜索。
然后调用searchTrack去搜索歌曲,订阅结果,最后显示结果通过renderResults
code/routes/music/app/ts/components/SearchComponent.ts
renderResults(res: any): void
this.results = null;
if (res && res.tracks && res.tracks.items)
this.results = res.tracks.items;
我们定义了一个results的属性,不管它何时更新,angular都会告知view去更新。
页面加载的时候搜索
当页面加载的时候,我们进行一次搜索:
code/routes/music/app/ts/components/SearchComponent.ts
ngOnInit(): void
this.search();
submit
让我们看看,当我们提交一个表单的时候做了什么?
code/routes/music/app/ts/components/SearchComponent.ts
submit(query: string): void
this.router.navigate(['/Search', query: query]);
this.search();
我们会手动导航到搜索栏,然后执行一个搜索操作。做这个事情的意义就是,当浏览器重新加载的时候,我们会看到相同的搜索结果。
合起来
code/routes/music/app/ts/components/SearchComponent.ts
/*
* Angular
*/
import Component, OnInit from '@angular/core';
import CORE_DIRECTIVES from '@angular/common';
import
Router,
RouterLink,
RouteParams,
from '@angular/router-deprecated';
/*
* Services
*/
import SpotifyService from 'services/SpotifyService';
@Component(
selector: 'search',
directives: [RouterLink, CORE_DIRECTIVES],
template: `
<h1>Search</h1>
<p>
<input type="text" #newquery
[value]="query"
(keydown.enter)="submit(newquery.value)">
<button (click)="submit(newquery.value)">Search</button>
</p>
<div *ngIf=(播放框架2.4)在客户端反向路由图像?