模板表達(dá)式“{{}}”不能引用任何全局命名空間中的成員(如:window、document等等)的原因:
我想原因可能是:
- 為了防止名稱(chēng)沖突民珍,angular在解析模板表達(dá)式后败去,會(huì)把表達(dá)式中的每個(gè)變量var替換成模板所屬類(lèi)的實(shí)例instance的屬性調(diào)用instance.var放航;
所以如果引用全局命名空間中的成員的話,如:document圆裕,解析后就會(huì)變成:instance.document广鳍,而instance.document是不存在的,所以就引發(fā)了錯(cuò)誤吓妆;
數(shù)據(jù)綁定
組件類(lèi)和模板之間的數(shù)據(jù)交互稱(chēng)為數(shù)據(jù)綁定赊时;它是一種讓模板的各部分與組件的各部分相互合作的機(jī)制;
數(shù)據(jù)綁定的語(yǔ)法有四種形式行拢。每種形式都有一個(gè)方向:綁定到DOM祖秒、綁定自DOM 或者及雙向綁定。
-
{{expression}}
插值剂陡; -
[屬性]
屬性綁定狈涮; -
(事件)
事件綁定; -
[(屬性)]
雙向綁定鸭栖;本質(zhì)上是結(jié)合屬性綁定和事件綁定的語(yǔ)法糖歌馍;
屬性綁定、事件綁定晕鹊、插值也屬于數(shù)據(jù)綁定的東范疇松却;屬性綁定和事件綁定即可用于父子組件的傳遞,也可用于組件的數(shù)據(jù)模型和模板視圖之間的數(shù)據(jù)傳遞溅话;所以在父子組件通信的過(guò)程中晓锻,模板充當(dāng)類(lèi)似于橋梁的角色,連接二者的功能邏輯飞几,如下圖:
Angular的數(shù)據(jù)流動(dòng)機(jī)制是靠Angular的變化監(jiān)測(cè)機(jī)制驅(qū)動(dòng)著的砚哆;
插值
- 插值語(yǔ)法是由一對(duì)雙大括號(hào)
{{}}
組成,插件是一半向的數(shù)據(jù)流動(dòng)——從數(shù)據(jù)模型到模板視圖屑墨;插值中的變量上下文是組件類(lèi)本身躁锁; - 插值表達(dá)式可以把計(jì)算后的字符串插入到 HTML 元素標(biāo)簽內(nèi)的文本或?qū)?biāo)簽的屬性進(jìn)行賦值纷铣。
- 一般來(lái)說(shuō),括號(hào)間的素材是一個(gè)模板表達(dá)式战转,Angular 先對(duì)它求值搜立,再把它轉(zhuǎn)換成字符串。
- 插值表達(dá)式是一個(gè)特殊的語(yǔ)法槐秧,Angular 會(huì)把它轉(zhuǎn)換成屬性綁定啄踊。
變化監(jiān)測(cè)
Angular并不是用ES5提供的getter、setter語(yǔ)言接口來(lái)實(shí)現(xiàn)變化監(jiān)測(cè)的刁标,而是以適當(dāng)?shù)臅r(shí)機(jī)去檢驗(yàn)對(duì)呀的值是否被改動(dòng)颠通,這個(gè)適當(dāng)?shù)臅r(shí)機(jī)并不是以固定的某個(gè)頻率去執(zhí)行檢驗(yàn),而通常是在用戶(hù)操作事件(如:?jiǎn)螕羰录┟浮etTimeout或XHR回調(diào)等這些異步事件觸發(fā)之后蒜哀;Angular捕獲這些異步事件的工作是通過(guò)Zones庫(kù)實(shí)現(xiàn)的;
如下圖所示:第個(gè)組件背后都維護(hù)著一個(gè)獨(dú)立的變化監(jiān)測(cè)器吏砂,這個(gè)變化監(jiān)測(cè)器記錄著所屬組件的數(shù)據(jù)變更狀態(tài)。由于應(yīng)用是以組件樹(shù)的形式組織乘客,因此第個(gè)應(yīng)用也有著對(duì)應(yīng)的一棵變化監(jiān)測(cè)樹(shù)狐血。當(dāng)Zones的捕獲到某異步事件后,它都會(huì)通知Angular執(zhí)行變化監(jiān)測(cè)操作易核,每次變化監(jiān)測(cè)操作都始于根組件匈织,并以深度優(yōu)先的原則向葉組件遍歷執(zhí)行。
給Angular的屬性的各個(gè)賦值的方式的區(qū)別:
假設(shè):組件A的子組件B的屬性有attrB牡直;
則在組件A的模板中給子組件B的attrB屬性賦值的方式如下:
- 通過(guò)輸入綁定語(yǔ)法”[ ]":<B [attrB]="value" ></B>缀匕;這種方法會(huì)有以下特點(diǎn):
- 只把a(bǔ)ttrB當(dāng)作輸入屬性對(duì)待,所以只能用于當(dāng)元素B有輸入屬性attrB時(shí)碰逸;若元素B沒(méi)有輸入屬性attrB乡小,則會(huì)報(bào)錯(cuò);
- 會(huì)把value當(dāng)作表達(dá)式進(jìn)行計(jì)算饵史,然后把表達(dá)式value的值綁定到attrB上满钟,即使value不被引號(hào)包裹,也會(huì)把value當(dāng)作表達(dá)式胳喷;
- 當(dāng)把[attrB]=“value"的賦值操作去掉湃番,只寫(xiě)[attrB]時(shí),不會(huì)執(zhí)行對(duì)attrB的賦值操作吭露;
- 通過(guò)標(biāo)簽屬性賦值語(yǔ)法:<B attrB="value" ></B>吠撮;這種方法會(huì)有以下特點(diǎn):
- 分別把a(bǔ)ttrB當(dāng)作各種匹配的特性對(duì)待;例如:當(dāng)attrB可以作為標(biāo)簽的屬性讲竿,又是一個(gè)指令泥兰,同時(shí)又是一個(gè)輸入屬性時(shí)择浊,剛會(huì)分別對(duì)標(biāo)簽屬性attrB和輸入屬性attrB進(jìn)行賦值,并且使指令attrB生效逾条;
- 會(huì)把等號(hào)“=”右邊的”value”當(dāng)作字符串賦值到attrB上琢岩,即使value不被引號(hào)包裹,也會(huì)把value當(dāng)作純字符串师脂;
- 當(dāng)把a(bǔ)ttrB=“value”的賦值操作去掉担孔,只寫(xiě)attrB時(shí),會(huì)對(duì)attrB的進(jìn)行賦值吃警,值為空字符串“”糕篇,即相當(dāng)于:attrB="";
給Angular的輸出屬性賦值的實(shí)際意義:
假設(shè):組件A的子組件B的輸出屬性是attrB酌心;
則在組件A的模板中給子組件B的attrB輸出屬性賦值的方式為:(attrB)="expression"拌消,其中包裹attrB的圓括號(hào)是必須的,無(wú)論expression有沒(méi)有被引號(hào)包裹安券,expression都會(huì)被當(dāng)作是表達(dá)式墩崩,并且這個(gè)表達(dá)式是被放在Angular自動(dòng)創(chuàng)建的回調(diào)函數(shù)的上下文中執(zhí)行的,即expression被作為Angular自動(dòng)創(chuàng)建的回調(diào)函數(shù)的代碼執(zhí)行的侯勉,并且這個(gè)回調(diào)函數(shù)擁有局部變量$event($event極有可能是該回調(diào)函數(shù)的參數(shù))鹦筹,$event是調(diào)用EventEmitter的實(shí)例方法emit時(shí)傳入的參數(shù),所以expression中可以引用$event址貌;
@ViewChild()裝飾器:
- 當(dāng)向@ViewChild()裝飾器中傳入一個(gè)類(lèi)型Type時(shí)铐拐,被裝飾的量引用的是類(lèi)型Type的第一個(gè)子組件;
- 當(dāng)向@ViewChild()裝飾器中傳入一個(gè)字符串時(shí)练对,被裝飾的量引用的是字符串所對(duì)應(yīng)的模版局部變量遍蟋;
組件內(nèi)容嵌入:
對(duì)于符合嵌入的內(nèi)容則會(huì)被嵌入,不符合的內(nèi)容會(huì)被從Dom樹(shù)中移除螟凭;
Angular中三種指令的側(cè)重點(diǎn):
指令的作用是增強(qiáng)模板特性虚青,間接地?cái)U(kuò)散模板語(yǔ)法;
各種指令的側(cè)重點(diǎn):
- 屬性指令:擴(kuò)展元素的屬性赂摆,通常被用來(lái)改變?cè)氐耐庥^和行為挟憔;
- 結(jié)構(gòu)指令:擴(kuò)展元素的屬性,用來(lái)改變DOM樹(shù)的結(jié)構(gòu)烟号;
- 組件:擴(kuò)展元素的標(biāo)簽绊谭,用來(lái)自定義標(biāo)簽;
備注:
雖然指令常用來(lái)擴(kuò)展屬性汪拥,組件常用來(lái)擴(kuò)展標(biāo)簽达传,但是它們的選擇器的定義是任意的,所以,組件的選擇器也可以定義成屬性選擇器宪赶,從而以屬性的形式使用組件宗弯,指令的選擇器也可以定義成標(biāo)簽選擇器,從而以標(biāo)簽的形式使用指令搂妻;
性能優(yōu)化方法:
- 縮小變化監(jiān)測(cè)范圍蒙保;
通過(guò)變化監(jiān)測(cè)類(lèi)ChangeDetectorRef的實(shí)例的markForCheck(): void方法標(biāo)記變化監(jiān)測(cè)的路徑為根組件到該組件; - 縮小變化監(jiān)測(cè)時(shí)間欲主;
通過(guò)變化監(jiān)測(cè)類(lèi)ChangeDetectorRef的實(shí)例的detach(): void 分離變化監(jiān)測(cè)器邓厕,然后在適當(dāng)?shù)臅r(shí)機(jī)通過(guò) detectChanges(): void 手動(dòng)監(jiān)測(cè)變化 或者 通過(guò)reattach(): void 再重新安裝上變化監(jiān)測(cè)器; - 變化監(jiān)測(cè)策略能用OnPush的不用Default扁瓢;
- 模板中的表達(dá)式的計(jì)算量能少則少详恼;因?yàn)锳ngular的變化監(jiān)測(cè)機(jī)制,使得模板中的表達(dá)式執(zhí)行頻率很高引几;
- 盡量使用NgForTrackBy指令來(lái)替代NgFor指令昧互;
服務(wù)
- providers配置選項(xiàng)是依賴(lài)注入操作的關(guān)鍵,它會(huì)為該組件創(chuàng)建一個(gè)注入器對(duì)象伟桅,并新建相應(yīng)服務(wù)的實(shí)例存儲(chǔ)到這個(gè)注入器里敞掘,當(dāng)需要引入相應(yīng)服務(wù)的實(shí)例時(shí),通過(guò)TypeScript的類(lèi)型匹配即可從注入器取出相應(yīng)的服務(wù)實(shí)例對(duì)象贿讹;
- 服務(wù)的每一 次溈(也就是一使用providers聲明)渐逃,該服務(wù)都會(huì)被建出新的實(shí)例,組件的所有子組件均默認(rèn)繼承父組件的注入器對(duì)象民褂,復(fù)用該注入器里存儲(chǔ)的服務(wù)實(shí)例。這種機(jī)制可以保證服務(wù)以單例模式運(yùn)行疯潭,除非某個(gè)子組件再次注入(即通過(guò)providers選項(xiàng)聲明)赊堪;
- 因?yàn)樗心K(這里指Angular應(yīng)用級(jí)別的模塊,并非ES6語(yǔ)言中的模塊)都共享著同一個(gè)應(yīng)用級(jí)別的根注入器竖哩,所以哭廉,當(dāng)把服務(wù)注入到模塊里時(shí),該服務(wù)在整個(gè)應(yīng)用里均能使用相叁;
路由
路由的作用是建立URL路徑和組件之間的對(duì)應(yīng)關(guān)系遵绰,根據(jù)不同的URL路徑匹配出相應(yīng)的組件渲染;
Angular應(yīng)用的引導(dǎo)啟動(dòng)
Angular通過(guò)引導(dǎo)運(yùn)行根模塊來(lái)啟動(dòng)應(yīng)用增淹,引導(dǎo)的方式有2種:
- 動(dòng)態(tài)引導(dǎo)椿访;
- 靜態(tài)引導(dǎo);
Angular應(yīng)用運(yùn)行之前虑润,都需要經(jīng)過(guò)編譯器對(duì)模塊成玫、組件等進(jìn)行編譯,編譯完成后才開(kāi)始啟動(dòng)應(yīng)用并渲染界面;
動(dòng)態(tài)引導(dǎo)和靜態(tài)引導(dǎo)的區(qū)別就在于編譯的時(shí)機(jī)不同哭当,動(dòng)態(tài)引導(dǎo)是將所有代碼加載到瀏覽器后猪腕,在瀏覽器進(jìn)行編譯;而靜態(tài)引導(dǎo)是將編譯過(guò)程前置到開(kāi)發(fā)時(shí)的工程打包階段钦勘;
由于靜態(tài)引導(dǎo)應(yīng)用時(shí)陋葡,整個(gè)應(yīng)用已經(jīng)被預(yù)先編譯,所以編譯器并不并不會(huì)被打包到項(xiàng)目代碼彻采,這使得代碼包體積更小腐缤,加載更快,而且也省去了瀏覽器編譯這個(gè)步驟颊亮,因此應(yīng)用的啟動(dòng)速度也會(huì)更快柴梆;
動(dòng)態(tài)引導(dǎo)開(kāi)發(fā)流程簡(jiǎn)明了,適合在 小型項(xiàng)目 或者 大型應(yīng)用的開(kāi)發(fā)階段 中使用终惑,而靜態(tài)引導(dǎo)需要在開(kāi)發(fā)階段加入預(yù)編譯流程绍在,稍顯復(fù)雜但性能提升明顯,推薦使用雹有;
模板
- 模板中的script標(biāo)簽會(huì)被忽略偿渡;
- html、body霸奕、base等標(biāo)簽在模板中是無(wú)用的溜宽;
模板表達(dá)式
模板表達(dá)式是指在模板中使用的表達(dá)式;比如插值中的表達(dá)式质帅、屬性綁定中等號(hào)右邊的表達(dá)式等等适揉。
模板表達(dá)式產(chǎn)生一個(gè)值。 Angular 執(zhí)行這個(gè)表達(dá)式煤惩,并把它賦值給綁定目標(biāo)的屬性嫉嘀,這個(gè)綁定目標(biāo)可能是 HTML 元素、組件或指令魄揉。
很多 JavaScript 表達(dá)式也是合法的模板表達(dá)式剪侮,但不是全部。
JavaScript 中那些具有或可能引發(fā)副作用的表達(dá)式是被禁止的洛退,包括:
賦值 (=, +=, -=, ...)
new運(yùn)算符
使用;或,的鏈?zhǔn)奖磉_(dá)式
自增或自減操作符 (++和--)
和 JavaScript語(yǔ) 法的其它顯著不同包括:
不支持位運(yùn)算|和&
具有新的模板表達(dá)式運(yùn)算符瓣俯,比如|、?.和!兵怯。
表達(dá)式上下文
典型的表達(dá)式上下文就是這個(gè)組件實(shí)例彩匕,它是各種綁定值的來(lái)源;
表達(dá)式中的上下文變量是由模板變量摇零、指令的上下文變量(如果有)和組件的成員疊加而成的推掸。 如果我們要引用的變量名存在于一個(gè)以上的命名空間中桶蝎,那么,模板變量是最優(yōu)先的谅畅,其次是指令的上下文變量登渣,最后是組件的成員。
模板表達(dá)式不能引用全局命名空間中的任何東西毡泻,比如window或document胜茧。它們也不能調(diào)用console.log或Math.max。 它們只能引用表達(dá)式上下文中的成員仇味。
表達(dá)式應(yīng)該遵循下列指南:
- 沒(méi)有可見(jiàn)的副作用
- 執(zhí)行迅速
- 非常簡(jiǎn)單
- 冪等性
模板語(yǔ)句
模板語(yǔ)句用來(lái)響應(yīng)由綁定目標(biāo)(如 HTML 元素呻顽、組件或指令)觸發(fā)的事件。 模板語(yǔ)句將在事件綁定一節(jié)看到丹墨,它出現(xiàn)在=號(hào)右側(cè)的引號(hào)中廊遍,就像這樣:(event)="statement"。
模板語(yǔ)句有副作用贩挣。 這是事件處理的關(guān)鍵喉前。因?yàn)槲覀円鶕?jù)用戶(hù)的輸入更新應(yīng)用狀態(tài)。
和模板表達(dá)式一樣王财,模板語(yǔ)句使用的語(yǔ)言也像 JavaScript卵迂。 模板語(yǔ)句解析器和模板表達(dá)式解析器有所不同,特別之處在于它支持基本賦值 (=) 和表達(dá)式鏈 (;和,)绒净。
然而见咒,某些 JavaScript 語(yǔ)法仍然是不允許的:
new運(yùn)算符
自增和自減運(yùn)算符:++和--
操作并賦值,例如+=和-=
位操作符|和&
模板表達(dá)式運(yùn)算符
語(yǔ)句上下文
和模板表達(dá)式中的上下文一樣挂疆;
動(dòng)畫(huà)
Angular動(dòng)畫(huà)是基于標(biāo)準(zhǔn)的Web動(dòng)畫(huà)API(Web Animations API)構(gòu)建的改览,它們?cè)谥С执薃PI的瀏覽器中會(huì)用原生方式工作。
至于其它瀏覽器缤言,就需要一個(gè)填充庫(kù)(polyfill)了恃疯。你可以從這里獲取web-animations.min.js,并把它加入你的頁(yè)面中墨闲。
模塊
Angular 應(yīng)用是模塊化的,并且 Angular 有自己的模塊系統(tǒng)郑口,它被稱(chēng)為 Angular 模塊或 NgModules鸳碧。
Angular 模塊(無(wú)論是根模塊還是特性模塊)都是一個(gè)帶有@NgModule裝飾器的類(lèi);
NgModule是一個(gè)裝飾器函數(shù)犬性,它接收一個(gè)用來(lái)描述模塊屬性的元數(shù)據(jù)對(duì)象瞻离。其中最重要的屬性是:
- declarations - 聲明本模塊中擁有的視圖類(lèi)。Angular 有三種視圖類(lèi):組件乒裆、指令和管道套利。
- exports - declarations 的子集,可用于其它模塊的組件模板。
- imports - 本模塊聲明的組件模板需要的類(lèi)所在的其它模塊肉迫。
- providers - 服務(wù)的創(chuàng)建者验辞,并加入到全局服務(wù)列表中,可用于應(yīng)用任何部分喊衫。
- bootstrap - 指定應(yīng)用的主視圖(稱(chēng)為根組件)跌造,它是所有其它視圖的宿主。只有根模塊才能設(shè)置bootstrap屬性族购。
- 每個(gè) Angular 應(yīng)用至少有一個(gè)模塊(根模塊)壳贪;
- 根模塊不需要導(dǎo)出任何東西,因?yàn)槠渌M件不需要導(dǎo)入根模塊寝杖。
- NgModules 和 JavaScript 模塊的比較:
- NgModules是應(yīng)用級(jí)別的模塊违施,是以功能特性為劃分依據(jù);
- JavaScript中的模塊是語(yǔ)言級(jí)別的模塊瑟幕,是以物理文件或者文件夾為劃分依據(jù)磕蒲;
組件
組件是一個(gè)帶模板的指令;@Component裝飾器實(shí)際上就是一個(gè)@Directive裝飾器收苏,只是擴(kuò)展了一些面向模板的特性亿卤。
依賴(lài)注入
“依賴(lài)注入”是提供類(lèi)的新實(shí)例的一種方式,還負(fù)責(zé)處理好類(lèi)所需的全部依賴(lài)鹿霸。大多數(shù)依賴(lài)都是服務(wù)排吴。 Angular 使用依賴(lài)注入來(lái)提供新組件以及組件所需的服務(wù)。
Angular 通過(guò)查看構(gòu)造函數(shù)的參數(shù)類(lèi)型得知組件需要哪些服務(wù)懦鼠。
當(dāng) Angular 創(chuàng)建組件時(shí)钻哩,會(huì)首先為組件所需的服務(wù)請(qǐng)求一個(gè)注入器 (injector)。
注入器是一個(gè)維護(hù)服務(wù)實(shí)例的容器肛冶,存放著以前創(chuàng)建的服務(wù)實(shí)例街氢。 如果所請(qǐng)求的服務(wù)實(shí)例不在容器中,注入器就會(huì)新創(chuàng)建一個(gè)服務(wù)實(shí)例睦袖,并且添加到容器中珊肃,然后把這個(gè)服務(wù)返回給 Angular。 當(dāng)所有請(qǐng)求的服務(wù)都被解析完并返回時(shí)馅笙,Angular 會(huì)把這些服務(wù)作為參數(shù)去調(diào)用組件的構(gòu)造函數(shù)伦乔。 這就是依賴(lài)注入 。
如果注入器還沒(méi)有HeroService董习,它怎么知道該如何創(chuàng)建一個(gè)呢烈和?
簡(jiǎn)單點(diǎn)說(shuō),我們必須先用注入器(injector)為服務(wù)注冊(cè)一個(gè)提供商(provider)皿淋。 提供商用來(lái)創(chuàng)建或返回服務(wù)實(shí)例招刹,通常就是這個(gè)服務(wù)類(lèi)本身的實(shí)例(相當(dāng)于new 服務(wù)())恬试。
需要記住的關(guān)于依賴(lài)注入的要點(diǎn)是:
- 依賴(lài)注入滲透在整個(gè) Angular 框架中,被到處使用疯暑。
- 注入器 (injector) 是本機(jī)制的核心训柴。
- 注入器負(fù)責(zé)維護(hù)一個(gè)容器,用于存放它創(chuàng)建過(guò)的服務(wù)實(shí)例缰儿。
- 注入器能使用提供商創(chuàng)建一個(gè)新的服務(wù)實(shí)例畦粮。
- 提供商是一個(gè)用于創(chuàng)建服務(wù)的配方。
- 把提供商注冊(cè)到注入器乖阵。
編程思想
- 組件類(lèi)應(yīng)保持精簡(jiǎn)宣赔。組件本身不從服務(wù)器獲得數(shù)據(jù)、不進(jìn)行驗(yàn)證輸入瞪浸,也不直接往控制臺(tái)寫(xiě)日志儒将。 它們把這些任務(wù)委托給服務(wù)。
- 組件的任務(wù)就是提供用戶(hù)體驗(yàn)对蒲,僅此而已钩蚊。它介于視圖(由模板渲染)和應(yīng)用邏輯(通常包括模型的某些概念)之間。 設(shè)計(jì)良好的組件為數(shù)據(jù)綁定提供屬性和方法蹈矮,把其它瑣事都委托給服務(wù)砰逻。