当前位置:澳门贵宾厅 > 澳门贵宾厅 > Title 服务注入到组件中,作为组件功能的扩展.
Title 服务注入到组件中,作为组件功能的扩展.
2020-05-06

时间: 2019-12-15阅读: 62标签: Angular

简述:一个完整的Angular应用主要由六个重要部分构成,分别是:组件,模板,指令,服务,依赖注入,和路由.这些组成部分各司其职,而又紧密协作.

如果你已经是编写 Angular 应用的”老手“,可能会觉得这篇文章介绍的这些特性自己肯定都很熟悉。但事实未必如此,不信的话等你看完再说。

其中,与用户直接打交互的是模板视图,它是构成组件的要素之一.另一要素是组件类,用以维护组件的数据模型及功能逻辑.

  1. Title

路由的功能是控制组件的创建和销毁,从而驱使应用界面跳转切换/

Title 标签是一个 HTML 元素,用于指定网页标题。Title 标签作为给定结果的可点击标题,显示在搜索引擎结果页面(SERP)上。它们对于可用性、SEO 和社交共享而言至关重要。

指令与模板相互关联,最重要的作用是增强模板特性,间接扩展了模板的语法.

Angular应用使用 index.html 中的,在浏览器窗口中设置标题。导航到 Angular 中的组件不会更改标题。

服务是封装了若干功能逻辑的单元,这个功能逻辑可以通过依赖注入机制引入到组件内部,作为组件功能的扩展.

那么你知道吗,其实可以通过组件来设置浏览器标题。

在Angular应用接受用户指令,加工处理后输出相应视图过程中,组件始终处于这个交互的出入口,这是Angular基于组件设计的体现.

Angular 在 @angular/platform-browser 中有一个 Title 服务。我们只需将 Title 服务注入到组件中,并使用 setTitle 方法设置标题即可。

1. 组件:组件在Angular框架中处于最核心的位置,Angular框架基于组件设计,其应用由一系列大大小小的松耦合的组件构成.Angular的模板里可以直接引用组件的成员属性,

import { Title } from "@angular/platform-browser"@Component({ ...})export class LoginComponent implements OnInit { constructor(private title: Title) {} ngOnInit() { title.setTitle("Login") }}

组件类和模板成员之间的数据交互称为数据绑定(属性绑定和事件绑定也属于数据绑定的范畴).属性绑定和事件绑定即可用于父子组件的数据传递,也可用于组件数据模型和

当我们导航到 LoginComponent 时,浏览器的标题将设置为“Login”。

视图之间的数据传递.所以在父子组件通信过程中,模板从党类似于桥梁的角色.

我们可以在项目的所有组件中重复这一操作,这样在导航到它们的位置时,浏览器窗口将更改为组件设置的标题。

Angular是一个响应式系统,每次数据变动几乎都能实现实时处理,并更新对应视图.Angular是以适当的时机去检验对象的值是否被改动,这个适当时机并不是以固定的频率

  1. Meta

去执行,而通常是在用户操作事件(如单机),setTimeout或XHR回调等这些异步事件触发之后.Angular捕获这些异步事件的工作是通过Zons库来实现的.

我们的 Angular 应用渲染的内容大部分来自于 index.html。我们的应用会拥有在 index.html 中设置的一个 meta 标签。Angular 在 @angular/platform-browser 中有一个 Meta 服务,使我们能够从组件中设置 meta 标签。

每个组件背后都维护着一个独立的变化监测器,这个变化监测器记录着所属组件的数据变更状态.由于应用是以组件树的形式组织,因此每个应用也有着对应的一棵变化监测树.

这是很有用的功能,可以更好地进行搜索引擎优化(SEO),也可以将组件拥有的页面共享给社交媒体。

当Zones捕获到某异步事件后,它都会通知Angular执行变化监测操作,每次变化监测操作都始与根组件,并以深度优先的原则向叶子组件遍历执行.

根据维基百科的定义:

变化监测机制使得开发者不必关心数据和变动,结合数据绑定实现模板视图实时更新,这就是Angular强大的数据变化监测机制.变化监测机制提供数据自动更新功能,若需要手动

Meta是 HTML 和 XHTML 文档中使用的标签,用于提供网页的结构化元数据。它们是网页 head 的一部分,可以在同一页面上使用具有不同属性的多个 Meta 元素。Meta 元素可用于指定页面描述、关键字,以及其他 head 元素和属性未提供的元数据。

捕获变化事件做一些额外处理,Angular还提供了完善的生命周期钩子给开发者调用,如ngOnChanges可以满足刚提到的捕获变化事件要求,如ngOnDestroy可以在组件销毁前做一些
清理工作.

Meta 元素提供有关网页的信息,搜索引擎可以在这些信息的帮助下正确地分类网页。

2. 模板:Angular模板基于Html,普通的Html亦可作为模板输入.Angular为模板定制出一套强大的语法体系,数据绑定是模板的基本功能,插值也是很常见的数据绑定的语法.插值语法是由

它用起来非常容易,只需从 @angular/platform-browser 导入 Meta,并将其注入到我们的组件中即可。

一对双大括号{{}}组成,插值的变量上下文是组件类本身,
如:export class contactComponet{ @Input() item:ContractMOdel;... }

import { Meta } from "@angular/platform-browser"@Component({ ...})export class BlogComponent implements OnInit { constructor(private meta: Meta) {} ngOnInit() { meta.updateTag({name: "title", content: ""}) meta.updateTag({name: "description", content: "Lorem ipsum dolor"}) meta.updateTag({name: "image", content: "./assets/blog-image.jpg"}) meta.updateTag({name: "site", content: "My Site"}) }}

插值是一种单向的数据流动--从数据模型到模板视图,前面提到的三种数据绑定(即属性绑定,事件绑定以及插值)语法的数据流动都是单向的,在某些场景下需要双向的数据流动支持(如表单).

有了它,我们的 BlogComponent 可以渲染在 Facebook 和 Twitter 等网页上,并带有我们组件的描述信息,提供标题、图像和注释。

结合属性绑定和事件绑定,Angular模板可实现双向绑定的功能.
如:<input [(ngModel)]="contact.name" />

这个你也听过吗?

[()]是实现双向绑定的语法糖,ngModel是辅助实现双向绑定的内置指令.

  1. 覆盖模板插值

管道:数据绑定负责数据的传递与展示,而针对数据的格式化显示,Angular提供了管道功能,使用竖线|来表示,
如:<span>{{ contact.telephone | phone }}</span>

我们都在模板中使用默认模板插值器{{}}来显示组件中的属性。

angular模板还有很多强大的语法特性,包括上述提到的组件所封装的自定义标签<contact></contact>.

开头为{{,结尾为}}。如果我们在它们之间放置一个属性成员,它将渲染在浏览器 DOM 上。

3. 指令:指令与模板的关系密切,指令可以与DOM进行灵活交互,它或是改变样式,或是改变布局.指令的范畴很广,实际上组件也是指令的一种.组件与一般的指令的区别在于:组件带有单独的模板,即

你知道我们可以用自己的符号覆盖默认的封装开始和结束定界符吗?很简单,在 Component 装饰器的 interpolation 属性中指定即可。

DOM元素,而一般的指令作用在已有的DOM元素上.
一般指令分为两种:
1. 结构指令:结构指令能添加,修改或删除DOM,从而改变布局.
如:<button *ngIf="canEdit">编辑</button>

@Component({ interpolation: ["((","))"]})export class AppComponent {

注意"*"号不能丢,这是语法中的一部分.
2. 属性指令:用来改变元素的外观或行为,使用起来跟普通的HTML元素属性基本相似.
如:<span [ngStyle]="setStyles()">{{contact.name}}</span>

AppComponent 模板中使用的插值将不再是“{{}}”,而是“(())”。

4. 服务:其是封装单一功能的单元,类似于工具库,常被引用到组件内部,作为组件的功能扩展.它可以是一个简单的字符串或JSON数据,也可以是一个函数,甚至一个类,几乎所有的对象都可以封装成
服务.

@Component({ template: ` div ((data)) /div `, interpolation: ["((","))"]})export class AppComponent { data: any = "dataVar"}

HTTP是Angular里常用的内置服务,它封装了一系列的异步数据请求接口,但与一般的接口不同,HTTP服务对外暴露的是Reactive Programming规范的接口,基于RxJS实现,严格贯彻响应
式编程思想.

在渲染时,将渲染“dataVar”以代替 ((data))。

5. 依赖注入:通过依赖注入机制,服务等模块可以被引入到任何一个组件中.可以说依赖注入是一种帮助开发者管理模块依赖的设计模式.

  1. Location

@Component装饰器中的providers属性是依赖注入操作的关键,它会为该组件创建一个注入器对象,并新建所需要注入的对象存储到这个注入器里.组件在需要引入该实例对象时,通过

我们可以使用 Location 服务获取当前浏览器窗口的 URL。根据所使用的 LocationStrategy,Location 将存储 URL 的路径或 URL 的哈希段。

TypeScript的类型匹配既可以从注入器取出相应的实例对象,无需重复显示实例化.

有了 Location,我们可以转到一个 URL,在平台的历史记录中向前或向后跳转,更改浏览器 URL,替换平台的历史记录栈中的顶部项等。

注意:服务的每一次注入(也就是使用providers的声明),该服务都会被创建出新的实例.组件的所有子组件均默认继承福组件的注入器对象,服用该注入器里存储的服务实例.

我们从 CommonModule 注入 Location 服务,就可以使用它了。

6. 路由:在Angular中路由的作用是建立URL路径和组件之间的对应关系,根据不同的URL路径匹配出相应的组件并渲染.
如:[

import { Location } from "@angular/common"@Component({ ...})export class AppComponent { constructor(private location: Location) {} navigatTo(url) { this.location.go(url) } goBack() { location.back() } goForward() { location.forward() }}

{path:'',component:ContactListComponent},

  1. DOCUMENT

{path:'record',component:RecordListComponent},
...
]

有时我们想要获取文档模型,以便我们可以从 Angular 应用中执行 DOM 操作。

注意:上面配置的第一项path的值为空,这表示默认路由.
模板如下:
<div>
<header></header>

使用 DOCUMENT 就可以做到这一点。DOCUMENT 是表示主要渲染上下文的 DI 令牌。在浏览器中这就是 DOM 文档。它以与环境无关的方式提供 DOM 操作。

<router-outlet></router-outlet>
<footer></footer>
</div>

注意:当应用程序上下文和渲染上下文不同时(例如将应用程序运行到 Web Worker 中时),Document 可能在应用程序上下文中不可用。

路由指令router-outlet起着类似于"插座"的作用,根据当前的URL路径,匹配插入对应的组件节点,实现了主体内容(页面)的刷新,这就是Angular路由最基本的功能.路由指还支持多重
嵌套,实现了子路由的功能.如:
[

假设我们在 html 中有一个元素:

{path:'',component:ContactListComponent},

canvas /canvas

{path:'record',component:RecordListComponent,children:[

我们可以注入 DOCUMENT 来获取画布 HTMLElement:

{path:'',component:AllRecordComponent},

@Component({})export class CanvasElement { constructor(@Inject(DOCUMENT) _doc: Document) {}}

{path:'miss',component:MIssRecordComponent}
]}
]

我们可以调用 getElementById(),获得画布的 HTMLElement。

7. 应用模块:Angular引入了模块机制,是对某些特定功能特性的封装,可能包含若干组件,指令,服务等,甚至拥有独立的路由配置.每个Angular应用至少拥有一个模块,一般需要有一个模块

@Component({})export class CanvasElement { constructor(@Inject(DOCUMENT) _doc: Document) {} renderCanvas() { this._doc.getElementById("canvas") }}

作为应用的入口.这个入口的模块称为根模块,通过引导运行根模块来启动Angular应用.
7.1 在Angular中,除了根模块外其他的模块类型有:
1.特性模块:(Feature Module),封装某个完整功能的模块.
2.共享模块:(Shared Module)封装一些公共构件的模块.
3.核心模块:(Core Module)存放应用级别核心构件的模块.

我们还可以使用 ElementRef 和模板引用来安全地执行此操作,理解即可。

通过将特性模块导入到根模块里,即可实现对该特性功能的引入,而模块之间的交互,由Angular处理,这中交互关系对于不同的模块构件各不相同:

警告:要小心!直接与 DOM 交互是危险的,并且可能带来 XSS 风险。6. @Attribute 装饰器

1.路由:特性模块也可以自带路由配置,当特性模块导入到根模块后,特性模块的路由配置会自动与根模块里的路由配置合并.

我们在 Angular 应用中主要使用 Component、Module 和 Directive 装饰器。

2.组件和指令:默认情况下模块内的组件和指令是私有的,也就是说特性模块被导入根模块后,根模块不能使用该特性模块里的组件和指令,除非该特性模块里暴露出了某些组件或者指令

我们有一个 Attribute 装饰器,它使我们能够消除对静态字符串的更改检测,这样在传递静态字符串时就不会降低性能了。

这些暴露出的组件和指令相当于模块的API.

Attribute 装饰器的值只检查一次,之后就不再检查了。它们的用法类似于 @Input 装饰器:

3.服务:服务的处理则有些特殊,通过依赖注入机制,服务同样可以注入到根模块里,但跟组件里的依赖注入的作用域不相同.注入到该组件的服务只能使用在该组件机器子组件上.而注入

@Component({ ...})export class BlogComponent { constructor(@Attribute("type") private type: string ) {}}

到模块里的服务则在整个应用里均能使用,因为所有模块都共享着同一个应用级别的根注入器.
7.2 Angular已经封装了不少常用的特性模块,如:

  1. HttpInterceptor

1.ApplicationModule:封装一些启动相关的工具.

就像美国的防空网一样,这是 Angular 中非常强大的功能。它会拦截 HttpRequest 并处理它们。

2.CommonModule:封装一些常用的内置指令和内置管道等.

大多数拦截器会在调用 next.handle(transformedReq),以将传出请求传递到链中的下一个拦截器之前对请求进行转换。

3.BrowserModule:封装在浏览器平台运行时一些工具库,同时将CommonModule和ApplicationModule打包导出,所以通常在使用时引入BrowserModule就可以了.

在极少数情况下,拦截器可能希望自己完全处理请求,而不是委托给链的其余部分。这种行为是允许的。

4.FormsModule和ReactiveFormsModule:封装表单相关的组件指令等.

HttpInterceptor 可用于:

5.RouterModule:封装路由相关的组件指令等.

认证缓存伪后端URL 转换修改标头

6.HttpModule:封装了网络请求相关的服务等.
7.3 Angular通过引导运行根模块来启动引用,引导的方式有两种:动态引导和静态引导.Angular应用运行之前,都需要经过编译器对模块,组件等进行编译,编译完成后才开始启动应用并
渲染截面.

它用起来很简单,首先创建一个服务并实现 HttpInterceptor 接口。

动态引导和静态引导的区别在于编译的时机,动态引导是将所有代码加载到浏览器后,在浏览器进行编译;而静态引导是将编译过程前置到开发时的工程打包阶段,加载浏览器的将是编译
后的代码.
1.动态引导代码:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.Module';

@Injectable()export class MockBackendInterceptor implements HttpInterceptor { constructor() {} intercept(req: HttpRequestany, next: HttpHandler): ObservableHttpEventany { ... }}

platformBrowserDynamic().bootstrapModule(AppModule);

然后将其它插入你的主模块中:

动态引导是从platformBrowserDynamic函数启动的,该函数从@angular/platform-browser-dynamic文件模块中导入,动态引导的模块AppModule需要启动的模块.
2.静态引导代码:
import { platformBrowser } from '@angular/platform-browser';
import { AppModuleNgFactory } from './app.module.ngFactory';

@NgModule({ ... providers: [ { provide: HTTP_INTERCEPTORS, useClass: MockBackendInterceptor, multi: true } ] ...})export class AppModule {

platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

  1. AppInitializer

静态引导以platformBrowser()函数启动,这个函数是从@angular/platfrom-browser文件模块中导入的,和动态引导不是同一个.静态引导启动的是AppModuleNgFactory模块,

有时我们确实希望在 Angular 应用启动时运行一段代码,这段代码可能会加载一些设置,比如加载缓存,加载配置或进行某些签入。AppInitialzer 令牌可以帮助你解决这一问题。

这是AppModule经过编译后处理后生成的模块(app.module文件编译后生成app.module.ngFactory文件),由于整个文件已经被预先编译,所以编译器并不会打包到项目代码,项目

APP_INITIALIZER:初始化应用时执行的函数。

代码包更小,加载更快,省去编译,启动更快.

它很容易使用。如果我们希望在 Angular 应用启动时执行以下 runSettings 函数:

总结:动态引导开发流程简单明了,适合小型项目或者大型应用的开发阶段使用,而静态引导需要在开发阶段加入预编译流程,稍显复杂但性能提升明显,推荐使用.

function runSettingsOnInit() { ...}

8. Angular源码结构:整个Angular框架的源码是基于ES6模块来组织的(这里的模块是语言级别的模块,而Angular中的模块是应用级别的模块).
Angular的主要架构模块介绍:

只需转到主要模块 AppModule,并将它添加到其 NgModule 装饰器中的 provider 部分:

1.@angular/core:存放核心代码,如变化检测机制,依赖注入机制,渲染等,核心功能的实现,装饰器(@Common,@Directive等)也会存放到这个模块.

@NgModule({ providers: [ { provide: APP_INITIALIZER, useFactory: runSettingsOnInit } ]})

2.@angular/common:存放一些常用的内置组件及内置指令等.

  1. 引导监听器

3.@angular/forms:存放表单相关的内置组件及内置指令等.

就像 AppInitializer 一样,Angular 还有一项功能,使我们能够在引导组件时进行侦听。它就是 APP_BOOTSTRAP_LISTENER。

4.@angular/http:存放网络请求相关的服务等.

通过此令牌提供的所有回调将为每个引导的组件调用。

5.@angular/router:存放路由相关的组件和指令等.

我们有很多理由来侦听组件引导,例如,Router 模块使用它来破坏和创建基于路由导航的组件。

6.@angular/platform-<x>:存放的是引导启动相关的工具.Angular支持在多个平台下运行,不同的平台都有对应的启动工具,这些启动工具会被封装到不同的模块里.

要使用 APP_BOOTSTRAP_LISTENER,请使用回调函数将其添加到 AppModule 的 provider 部分中:

@NgModule({ { provide: APP_BOOTSTRAP_LISTENER, multi: true, useExisting: runOnBootstrap } ...})export class AppModule {}
  1. NgPlural

复数表示是一个问题。我们需要一直根据单数 / 复数值来在我们的应用中正确定义语法。某些网站会使用 (s)。比如:

1 component(s) removed3 component(s) removed

读者应在阅读时自行删除或添加 (s)****。

Angular 在其 NgPlural 指令中为我们解决了这个问题。

NgPlural 基于数字值来添加 / 删除 DOM 子树,为复数量身定制。

显示与切换表达式值匹配的 DOM 子树,否则显示与切换表达式的复数类别匹配的 DOM 子树。

要使用此指令,你必须提供一个容器元素,该元素将 [ngPlural] 属性设置为一个 switch 表达式。具有 [ngPluralCase] 的内部元素将根据其表达式显示:

p [ngPlural]="components" ng-template ngPluralCase="=1"1 component removed/ng-template ng-template ngPluralCase="1"{{components}} components removed /ng-template /p

看到了吧,当显示“已删除的组件”数量时,我们使用 NgPlural 指令删除了 (s)。它将显示:

// if 1 component1 component removed// if 5 components5 components removed

小结

全篇看下来,有没有丧失信心、觉得自己老了?

不用担心,我们所有人都有知识盲区。上面所列的内容只是其中一部分,Angular 既庞大又复杂。可以试着查看其他 Angular 相关的内容,看看是否可以找出你以前从未听说过的特性。期待你的发现。

原文链接:10 Useful Angular Features You’ve Probably Never Used