Angular发现与理解

模板表达式“{{}}”不能引用任何全局命名空间中的成员(如:window、document等等)的原因:

我想原因可能是:

  1. 为了防止名称冲突,angular在解析模板表达式后,会把表达式中的每个变量var替换成模板所属类的实例instance的属性调用instance.var;

所以如果引用全局命名空间中的成员的话,如:document,解析后就会变成:instance.document,而instance.document是不存在的,所以就引发了错误;

数据绑定

组件类和模板之间的数据交互称为数据绑定;它是一种让模板的各部分与组件的各部分相互合作的机制;
数据绑定的语法有四种形式。每种形式都有一个方向:绑定到DOM、绑定自DOM 或者及双向绑定。

  • {{expression}}插值;
  • [属性]属性绑定;
  • (事件)事件绑定;
  • [(属性)]双向绑定;本质上是结合属性绑定和事件绑定的语法糖;

属性绑定、事件绑定、插值也属于数据绑定的东范畴;属性绑定和事件绑定即可用于父子组件的传递,也可用于组件的数据模型和模板视图之间的数据传递;所以在父子组件通信的过程中,模板充当类似于桥梁的角色,连接二者的功能逻辑,如下图:


angular数据流动.png

Angular的数据流动机制是靠Angular的变化监测机制驱动着的;

插值

  1. 插值语法是由一对双大括号{{}}组成,插件是一半向的数据流动——从数据模型到模板视图;插值中的变量上下文是组件类本身;
  2. 插值表达式可以把计算后的字符串插入到 HTML 元素标签内的文本或对标签的属性进行赋值。
  3. 一般来说,括号间的素材是一个模板表达式,Angular 先对它求值,再把它转换成字符串。
  4. 插值表达式是一个特殊的语法,Angular 会把它转换成属性绑定。

变化监测

Angular并不是用ES5提供的getter、setter语言接口来实现变化监测的,而是以适当的时机去检验对呀的值是否被改动,这个适当的时机并不是以固定的某个频率去执行检验,而通常是在用户操作事件(如:单击事件)、setTimeout或XHR回调等这些异步事件触发之后;Angular捕获这些异步事件的工作是通过Zones库实现的;

如下图所示:第个组件背后都维护着一个独立的变化监测器,这个变化监测器记录着所属组件的数据变更状态。由于应用是以组件树的形式组织,因此第个应用也有着对应的一棵变化监测树。当Zones的捕获到某异步事件后,它都会通知Angular执行变化监测操作,每次变化监测操作都始于根组件,并以深度优先的原则向叶组件遍历执行。

Angular变化监测.png

给Angular的属性的各个赋值的方式的区别:

假设:组件A的子组件B的属性有attrB;
则在组件A的模板中给子组件B的attrB属性赋值的方式如下:

  1. 通过输入绑定语法”[ ]":<B [attrB]="value" ></B>;这种方法会有以下特点:
    1. 只把attrB当作输入属性对待,所以只能用于当元素B有输入属性attrB时;若元素B没有输入属性attrB,则会报错;
    2. 会把value当作表达式进行计算,然后把表达式value的值绑定到attrB上,即使value不被引号包裹,也会把value当作表达式;
    3. 当把[attrB]=“value"的赋值操作去掉,只写[attrB]时,不会执行对attrB的赋值操作;
  2. 通过标签属性赋值语法:<B attrB="value" ></B>;这种方法会有以下特点:
    1. 分别把attrB当作各种匹配的特性对待;例如:当attrB可以作为标签的属性,又是一个指令,同时又是一个输入属性时,刚会分别对标签属性attrB和输入属性attrB进行赋值,并且使指令attrB生效;
    2. 会把等号“=”右边的”value”当作字符串赋值到attrB上,即使value不被引号包裹,也会把value当作纯字符串;
    3. 当把attrB=“value”的赋值操作去掉,只写attrB时,会对attrB的进行赋值,值为空字符串“”,即相当于:attrB="";

给Angular的输出属性赋值的实际意义:

假设:组件A的子组件B的输出属性是attrB;
则在组件A的模板中给子组件B的attrB输出属性赋值的方式为:(attrB)="expression",其中包裹attrB的圆括号是必须的,无论expression有没有被引号包裹,expression都会被当作是表达式,并且这个表达式是被放在Angular自动创建的回调函数的上下文中执行的,即expression被作为Angular自动创建的回调函数的代码执行的,并且这个回调函数拥有局部变量$event($event极有可能是该回调函数的参数),$event是调用EventEmitter的实例方法emit时传入的参数,所以expression中可以引用$event;

@ViewChild()装饰器:

  1. 当向@ViewChild()装饰器中传入一个类型Type时,被装饰的量引用的是类型Type的第一个子组件;
  2. 当向@ViewChild()装饰器中传入一个字符串时,被装饰的量引用的是字符串所对应的模版局部变量;

组件内容嵌入:

对于符合嵌入的内容则会被嵌入,不符合的内容会被从Dom树中移除;

Angular中三种指令的侧重点:

指令的作用是增强模板特性,间接地扩散模板语法;
各种指令的侧重点:

  1. 属性指令:扩展元素的属性,通常被用来改变元素的外观和行为;
  2. 结构指令:扩展元素的属性,用来改变DOM树的结构;
  3. 组件:扩展元素的标签,用来自定义标签;

备注:
虽然指令常用来扩展属性,组件常用来扩展标签,但是它们的选择器的定义是任意的,所以,组件的选择器也可以定义成属性选择器,从而以属性的形式使用组件,指令的选择器也可以定义成标签选择器,从而以标签的形式使用指令;

性能优化方法:

  1. 缩小变化监测范围;
    通过变化监测类ChangeDetectorRef的实例的markForCheck(): void方法标记变化监测的路径为根组件到该组件;
  2. 缩小变化监测时间;
    通过变化监测类ChangeDetectorRef的实例的detach(): void 分离变化监测器,然后在适当的时机通过 detectChanges(): void 手动监测变化 或者 通过reattach(): void 再重新安装上变化监测器;
  3. 变化监测策略能用OnPush的不用Default;
  4. 模板中的表达式的计算量能少则少;因为Angular的变化监测机制,使得模板中的表达式执行频率很高;
  5. 尽量使用NgForTrackBy指令来替代NgFor指令;

服务

  1. providers配置选项是依赖注入操作的关键,它会为该组件创建一个注入器对象,并新建相应服务的实例存储到这个注入器里,当需要引入相应服务的实例时,通过TypeScript的类型匹配即可从注入器取出相应的服务实例对象;
  2. 服务的每一 次沩(也就是一使用providers声明),该服务都会被建出新的实例,组件的所有子组件均默认继承父组件的注入器对象,复用该注入器里存储的服务实例。这种机制可以保证服务以单例模式运行,除非某个子组件再次注入(即通过providers选项声明);
  3. 因为所有模块(这里指Angular应用级别的模块,并非ES6语言中的模块)都共享着同一个应用级别的根注入器,所以,当把服务注入到模块里时,该服务在整个应用里均能使用;

路由

路由的作用是建立URL路径和组件之间的对应关系,根据不同的URL路径匹配出相应的组件渲染;

Angular应用的引导启动

Angular通过引导运行根模块来启动应用,引导的方式有2种:

  1. 动态引导;
  2. 静态引导;

Angular应用运行之前,都需要经过编译器对模块、组件等进行编译,编译完成后才开始启动应用并渲染界面;
动态引导和静态引导的区别就在于编译的时机不同,动态引导是将所有代码加载到浏览器后,在浏览器进行编译;而静态引导是将编译过程前置到开发时的工程打包阶段;
由于静态引导应用时,整个应用已经被预先编译,所以编译器并不并不会被打包到项目代码,这使得代码包体积更小,加载更快,而且也省去了浏览器编译这个步骤,因此应用的启动速度也会更快;
动态引导开发流程简明了,适合在 小型项目 或者 大型应用的开发阶段 中使用,而静态引导需要在开发阶段加入预编译流程,稍显复杂但性能提升明显,推荐使用;

模板

  1. 模板中的script标签会被忽略;
  2. html、body、base等标签在模板中是无用的;

模板表达式

模板表达式是指在模板中使用的表达式;比如插值中的表达式、属性绑定中等号右边的表达式等等。
模板表达式产生一个值。 Angular 执行这个表达式,并把它赋值给绑定目标的属性,这个绑定目标可能是 HTML 元素、组件或指令。
很多 JavaScript 表达式也是合法的模板表达式,但不是全部。
JavaScript 中那些具有或可能引发副作用的表达式是被禁止的,包括:

赋值 (=, +=, -=, ...)
new运算符
使用;或,的链式表达式
自增或自减操作符 (++和--)
和 JavaScript语 法的其它显著不同包括:

不支持位运算|和&
具有新的模板表达式运算符,比如|、?.和!。

表达式上下文

典型的表达式上下文就是这个组件实例,它是各种绑定值的来源;
表达式中的上下文变量是由模板变量、指令的上下文变量(如果有)和组件的成员叠加而成的。 如果我们要引用的变量名存在于一个以上的命名空间中,那么,模板变量是最优先的,其次是指令的上下文变量,最后是组件的成员。
模板表达式不能引用全局命名空间中的任何东西,比如window或document。它们也不能调用console.log或Math.max。 它们只能引用表达式上下文中的成员。

表达式应该遵循下列指南:

  • 没有可见的副作用
  • 执行迅速
  • 非常简单
  • 幂等性

模板语句

模板语句用来响应由绑定目标(如 HTML 元素、组件或指令)触发的事件。 模板语句将在事件绑定一节看到,它出现在=号右侧的引号中,就像这样:(event)="statement"。
模板语句有副作用。 这是事件处理的关键。因为我们要根据用户的输入更新应用状态。

和模板表达式一样,模板语句使用的语言也像 JavaScript。 模板语句解析器和模板表达式解析器有所不同,特别之处在于它支持基本赋值 (=) 和表达式链 (;和,)。

然而,某些 JavaScript 语法仍然是不允许的:

new运算符
自增和自减运算符:++和--
操作并赋值,例如+=和-=
位操作符|和&
模板表达式运算符

语句上下文

和模板表达式中的上下文一样;

动画

Angular动画是基于标准的Web动画API(Web Animations API)构建的,它们在支持此API的浏览器中会用原生方式工作。
至于其它浏览器,就需要一个填充库(polyfill)了。你可以从这里获取web-animations.min.js,并把它加入你的页面中。

模块

Angular 应用是模块化的,并且 Angular 有自己的模块系统,它被称为 Angular 模块或 NgModules。
Angular 模块(无论是根模块还是特性模块)都是一个带有@NgModule装饰器的类;
NgModule是一个装饰器函数,它接收一个用来描述模块属性的元数据对象。其中最重要的属性是:

  • declarations - 声明本模块中拥有的视图类。Angular 有三种视图类:组件、指令和管道。
  • exports - declarations 的子集,可用于其它模块的组件模板。
    • imports - 本模块声明的组件模板需要的类所在的其它模块。
  • providers - 服务的创建者,并加入到全局服务列表中,可用于应用任何部分。
  • bootstrap - 指定应用的主视图(称为根组件),它是所有其它视图的宿主。只有根模块才能设置bootstrap属性。
  1. 每个 Angular 应用至少有一个模块(根模块);
  2. 根模块不需要导出任何东西,因为其它组件不需要导入根模块。
  3. NgModules 和 JavaScript 模块的比较:
    1. NgModules是应用级别的模块,是以功能特性为划分依据;
    2. JavaScript中的模块是语言级别的模块,是以物理文件或者文件夹为划分依据;

组件

组件是一个带模板的指令;@Component装饰器实际上就是一个@Directive装饰器,只是扩展了一些面向模板的特性。

依赖注入

“依赖注入”是提供类的新实例的一种方式,还负责处理好类所需的全部依赖。大多数依赖都是服务。 Angular 使用依赖注入来提供新组件以及组件所需的服务。
Angular 通过查看构造函数的参数类型得知组件需要哪些服务。

当 Angular 创建组件时,会首先为组件所需的服务请求一个注入器 (injector)。

注入器是一个维护服务实例的容器,存放着以前创建的服务实例。 如果所请求的服务实例不在容器中,注入器就会新创建一个服务实例,并且添加到容器中,然后把这个服务返回给 Angular。 当所有请求的服务都被解析完并返回时,Angular 会把这些服务作为参数去调用组件的构造函数。 这就是依赖注入 。

如果注入器还没有HeroService,它怎么知道该如何创建一个呢?
简单点说,我们必须先用注入器(injector)为服务注册一个提供商(provider)。 提供商用来创建或返回服务实例,通常就是这个服务类本身的实例(相当于new 服务())。

需要记住的关于依赖注入的要点是:

  1. 依赖注入渗透在整个 Angular 框架中,被到处使用。
  2. 注入器 (injector) 是本机制的核心。
    • 注入器负责维护一个容器,用于存放它创建过的服务实例。
    • 注入器能使用提供商创建一个新的服务实例。
  3. 提供商是一个用于创建服务的配方。
  4. 把提供商注册到注入器。

编程思想

  1. 组件类应保持精简。组件本身不从服务器获得数据、不进行验证输入,也不直接往控制台写日志。 它们把这些任务委托给服务。
  2. 组件的任务就是提供用户体验,仅此而已。它介于视图(由模板渲染)和应用逻辑(通常包括模型的某些概念)之间。 设计良好的组件为数据绑定提供属性和方法,把其它琐事都委托给服务。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,591评论 18 139
  • Angular 2架构总览 - 简书http://www.jianshu.com/p/aeb11061b82c A...
    葡萄喃喃呓语阅读 1,478评论 2 13
  • Angular 2是一个帮助我们使用HTML和JavaScript构建客户端应用的框架。这个框架包含几个互相协作的...
    JasonQiao阅读 7,076评论 1 48
  • Quartz2D quartz2D 是一个二维绘图引擎,同时支持iOS和Mac OS X系统 (跨平台,纯C语言的...
    ssccsci阅读 298评论 0 1
  • "我们明天去找工作 今天就在我大舅家睡一晚"豆花说到"什么 可是你大舅家好像没有房间给我们睡啊"辛无不解的问 "你...
    ad3f5b2ba243阅读 228评论 0 0