講課內容

1、 上傳本地圖片顯示發生了unsage

  1. iframe 的 src 屬性是資源 URL 安全上下文,由於不可信源能夠在用戶不知情的狀況下執行某些不安全的操做。
  2. DomSanitizer 安全URL腳本訪問
  3. XSS :是網站 Angular 2 如何保護咱們免受 XSS 攻擊 Angular 2 中默認將全部輸入值視爲不受信任。當咱們經過 property,attribute,樣式,類綁定或插值等方式,將一個值從模板中插入到DOM中時,Angular 2 會自幫咱們清除和轉義不受信任的值。咱們來看一下具體示例: 報錯:unsafe value used in a resource URL context

在Angular4中,經過input:file上傳選擇圖片本地預覽的時候,經過window.URL.createObjectURL獲取的url賦值給image的src出現錯誤:css

WARNING: sanitizing unsafe URL value 下面介紹一下解決方法: html代碼: 1 2 <input type="file" (change)="fileChange($event)" > <img [src]="imgUrl" alt=""> 其中,change方法會在每次選擇圖片後調用,image的src必須經過屬性綁定的形式,使用插值表達式一樣會出錯html

import { Component, OnInit } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'前端

@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit {web

imgUrl;segmentfault

constructor( private sanitizer: DomSanitizer ){}promise

ngOnInit() { }瀏覽器

fileChange(event){ let file = event.target.files[0]; let imgUrl = window.URL.createObjectURL(file); let sanitizerUrl = this.sanitizer.bypassSecurityTrustUrl(imgUrl);安全

this.imgUrl = sanitizerUrl;
複製代碼

} } 首先,引入DomSanitizer,而後在構造器裏面注入, 最重要的就是把window.URL.createObjectURL生成的imgUrl經過santizer的bypassSecurityTrustUrl方法,將它轉換成安全路徑。 最後將生成的安全的url賦值給imgUrl,此時就沒有問題了~ https://blog.csdn.net/Neokekeke/article/details/78739035前端框架

template ng-template templateUrl

angular2

  • 神族
  • 人族
  • 蟲族
在真實的業務開發裏面,另外一個典型的嵌套組件就是 Tab 頁,如下代碼是很常見的: 若是沒有內容投影機制,想要這樣嵌套地使用自定義標籤也是不可能的。

內容投影存在的第二個意義與組件的封裝有關。

雖然 Angular 提供了 @Component 裝飾器讓開發者能夠自定義標籤,可是請不要忘記,自定義標籤畢竟與 HTML 原生標籤不同,原生 HTML 標籤上面默認帶有不少屬性、事件,而你本身定義標籤是沒有的。原生 HTML 標籤上面暴露的屬性和事件列表請參見 W3C 的規範。

從宏觀的角度看,全部的自定義標籤都只不過是一層「虛擬的殼子」,瀏覽器並不認識自定義標籤,真正渲染出來的仍是 div、form、input 之類的原生標籤。因此,自定義標籤只不過是一層邏輯上的抽象和包裝,讓人類更容易理解和組織本身的代碼而已。

既然如此,自定義標籤和 HTML 原生標籤之間的關係是什麼呢?本質上說,這是「裝飾模式」的一種應用,而內容投影存在的意義就是可讓這個「裝飾」的過程作得更加省力、更加優雅一些。 @ContentChildren(ChildTwoComponent) childrenTwo:QueryList;
// @ContentChild(ChildTwoComponent) // childTwo:ChildTwoComponent; /在ngAfterContentInit鉤子裏面訪問被投影進來的組件 @ViewChild 與 @ViewChildren
咱們能夠利用 @ViewChild 這個裝飾器來操控直屬的子組件。 在ngAfterViewInit這個鉤子裏面能夠直接訪問子組件

生命週期

  1. https://segmentfault.com/a/1190000010928087
  2. onPush策略變動檢測
  3. 變動檢測的策略 第2-5課:組件:生命週期鉤子 我不打算在這裏羅列 API,在官方網站上面有更詳細的描述和例子。

在這一節裏面咱們只討論如下4件事:

什麼是 UI 組件的生命週期? Angular 組件的生命週期有什麼特別的地方? OnPush 策略的使用方式。 簡要介紹髒檢查的實現原理。 UI 組件的生命週期 enter image description here

不管使用什麼樣的前端框架,只要編寫 UI 組件,生命週期都是必需要考慮的重要內容。請展開你的想象,若是讓你來設計 UI 系統,組件有幾個重要的階段必定是繞不開的,好比:

初始化( init )階段:在這個階段你須要把組件 new 出來,把一些屬性設置上去,等等這些操做。 渲染( render )階段:在這個階段需你要把組件的模板和數據結合起來,生成 HTML 標籤結構,而且要整合到現有的 DOM 樹裏面去。 存活階段:既然帶有 UI,那麼在組件的存活期內就必定會和用戶進行交互。通常來講,帶有 UI 的系統都是經過事件機制進行用戶交互的。也就是說,這個階段將會處理大量的用戶事件:鼠標點擊、鍵盤按鍵、手指觸摸。 銷燬( destory )階段:最後,組件使用完了,須要把一些資源釋放掉。最典型的操做:須要把組件上的全部事件所有清理乾淨,避免形成內存泄漏。 在組件生命的不一樣階段,框架通常會暴露出一些「接口」,開發者能夠利用這些接口來實現一些本身的業務邏輯。這種接口在有些框架裏面叫作「事件」,在 Angular 裏面叫作「鉤子」,但其底層的本質都是同樣的。

Angular 組件的生命週期鉤子 enter image description here

Angular 一共暴露了8個「鉤子」,構造函數不算。 並無組件或者指令會實現所有鉤子。 綠色的4個鉤子可能會被執行不少次,紫色的只會執行一次。 Content 和 View 相關的4個鉤子只對組件有效,指令上不能使用。由於在新版本的 Angular 裏面,指令不能帶有 HTML 模板。指令沒有本身的 UI,固然就沒有 View 和 Content 相關的「鉤子」了。 請不要在生命週期鉤子裏面實現複雜的業務邏輯,尤爲是那4個會被反覆執行的鉤子,不然必定會形成界面卡頓。 OnPush 策略 在真實的業務系統中,組件會構成 Tree 型結構,就像這樣:

enter image description here

當某個葉子組件上的數據模型發生變化以後,就像這樣:

enter image description here

這時候,Angular 將會從根組件開始,遍歷整顆組件樹,把全部組件上的 ngDoCheck() 方法都調用一遍:

enter image description here

請注意,默認狀況下,不管哪一個葉子組件上發生了變化,都會把整個組件樹遍歷一遍。若是組件樹很是龐大,嵌套很是深,很明顯會有效率問題。在絕大部分時間裏面,並不會出現每一個組件都須要刷新的狀況,根本沒有必要每次都去所有遍歷。因此 Angular 提供了一種叫作 OnPush 的策略,只要把某個組件上的檢測策略設置爲 OnPush,就能夠忽略整個子樹了,就像這樣:

enter image description here

很明顯,使用了 OnPush 策略以後,檢查效率將會得到大幅度的提高,尤爲在組件的數量很是多的狀況下:

enter image description here

Angular 內置的兩種變動檢測策略:

Default:不管哪一個組件發生了變化,從根組件開始全局遍歷,調用每一個組件上的 ngDoCheck() 鉤子。 OnPush:只有當組件的 @Input 屬性發生變化的時候才調用本組件的 ngDoCheck() 鉤子。 有一些開發者建議 Angular 項目組把 OnPush 做爲默認策略,可是目前尚未獲得官方支持,或許在將來的某個版本里面會進行修改。

瞭解一點點原理 若是你不想看到扯原理的內容,能夠跳過這一小段。

enter image description here

你們都知道,AngularJS 是第一個把「雙向數據綁定」這種設計帶到前端領域來的框架,「雙向數據綁定」最典型的場景就是對錶單的處理。

雙向數據綁定的目標很明確:數據模型發生變化以後,界面能夠自動刷新;用戶修改了界面上的內容以後,數據模型也會發生自動修改。

很明顯,這裏須要一種同步機制,在 Angular 裏面這種同步機制叫作「變動檢測」。

在老版本 AgnularJS 裏面,變動檢測機制實現得不太完善,常常會出現檢測不到變動的狀況,因此纔有了讓你們很厭煩的 $apply() 調用。

在新版本的 Angular 裏面再也不存在這個問題了,由於新版本的 Angular 使用 Zone.js 這個庫,它會把全部可能致使數據模型發生變動的狀況所有攔截掉,從而在數據發生變化的時候去通知 Angular 進行刷新。

有一些朋友可能會以爲奇怪,Zone.js 怎麼這麼牛叉?它內部究竟是怎麼玩的呢?

實際上要作到這一點並不複雜,由於在瀏覽器環境下,有可能致使數據模型發生變化的狀況只有3種典型的回調:

事件回調:鼠標、鍵盤、觸摸 定時器回調:setTimeout 和 setInterval Ajax 回調 Zone.js 覆蓋了全部原生實現,當開發者在調用這些函數的時候,並非調用的原生方法,而是調用的 Zone.js 本身的實現,因此 Zone.js 就能夠作一些本身的處理了。

變動檢測

概述 簡單來講變化檢測就是Angular用來檢測視圖與模型之間綁定的值是否發生了改變,當檢測到模型中綁定的值發生改變時,則同步到視圖上,反之,當檢測到視圖上綁定的值發生改變時,則回調對應的綁定函數。

什麼狀況下會引發變化檢測? 總結起來, 主要有以下幾種狀況可能也改變數據:

用戶輸入操做,好比點擊,提交等 請求服務端數據(XHR) 定時事件,好比setTimeout,setInterval 上述三種狀況都有一個共同點,即這些致使綁定值發生改變的事件都是異步發生的。若是這些異步的事件在發生時可以通知到Angular框架,那麼Angular框架就能及時的檢測到變化。

圖片描述

左邊表示將要運行的代碼,這裏的stack表示Javascript的運行棧,而webApi則是瀏覽器中提供的一些Javascript的API,TaskQueue表示Javascript中任務隊列,由於Javascript是單線程的,異步任務在任務隊列中執行。

具體來講,異步執行的運行機制以下:

全部同步任務都在主線程上執行,造成一個執行棧(execution context stack)。 主線程以外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之 中放置一個事件。 一旦"執行棧"中的全部同步任務執行完畢,系統就會讀取"任務隊列",看看裏面有哪些事件。那些對應的異步任務,因而結束等待狀態,進入執行棧,開始執行。 主線程不斷重複上面的第三步。 當上述代碼在Javascript中執行時,首先func1 進入運行棧,func1執行完畢後,setTimeout進入運行棧,執行setTimeout過程當中將回調函數cb 加入到任務隊列,而後setTimeout出棧,接着執行func2函數,func2函數執行完畢時,運行棧爲空,接着任務隊列中cb 進入運行棧獲得執行。能夠看出異步任務首先會進入任務隊列,當運行棧中的同步任務都執行完畢時,異步任務進入運行棧獲得執行。若是這些異步的任務執行前與執行後能提供一些鉤子函數,經過這些鉤子函數,Angular便能獲知異步任務的執行。

angular2 獲取變化通知 那麼問題來了,angular2是如何知道數據發生了改變?又是如何知道須要修改DOM的位置,準確的最小範圍的修改DOM呢?沒錯,儘量小的範圍修改DOM,由於操做DOM對於性能來講但是一件奢侈品。

在AngularJS中是由代碼scope.apply()或者scope.digest觸發,而Angular接入了ZoneJS,由它監聽了Angular全部的異步事件。

ZoneJS是怎麼作到的呢?

實際上Zone有一個叫猴子補丁的東西。在Zone.js運行時,就會爲這些異步事件作一層代理包裹,也就是說Zone.js運行後,調用setTimeout、addEventListener等瀏覽器異步事件時,再也不是調用原生的方法,而是被猴子補丁包裝事後的代理方法。代理裏setup了鉤子函數, 經過這些鉤子函數, 能夠方便的進入異步任務執行的上下文.

//如下是Zone.js啓動時執行邏輯的抽象代碼片斷 function zoneAwareAddEventListener() {...} function zoneAwareRemoveEventListener() {...} function zoneAwarePromise() {...} function patchTimeout() {...} window.prototype.addEventListener=zoneAwareAddEventListener; window.prototype.removeEventListener=zoneAwareRemoveEventListener; window.prototype.promise = zoneAwarePromise; window.prototype.setTimeout = patchTimeout; 變化檢測的過程 Angular的核心是組件化,組件的嵌套會使得最終造成一棵組件樹。Angular的變化檢測能夠分組件進行,每個Component都對應有一個changeDetector,咱們能夠在Component中經過依賴注入來獲取到changeDetector。而咱們的多個Component是一個樹狀結構的組織,因爲一個Component對應一個changeDetector,那麼changeDetector之間一樣是一個樹狀結構的組織.

另外,Angular的數據流是自頂而下,從父組件到子組件單向流動。單向數據流向保證了高效、可預測的變化檢測。儘管檢查了父組件以後,子組件可能會改變父組件的數據使得父組件須要再次被檢查,這是不被推薦的數據處理方式。在開發模式下,Angular會進行二次檢查,若是出現上述狀況,二次檢查就會報錯:Expression Changed After It Has Been Checked Error。而在生產環境中,髒檢查只會執行一次。

相比之下,AngularJS採用的是雙向數據流,錯綜複雜的數據流使得它不得很少次檢查,使得數據最終趨向穩定。理論上,數據可能永遠不穩定。AngularJS給出的策略是,髒檢查超過10次,就認爲程序有問題,再也不進行檢查。

圖片描述

變化檢測策略 Angular有兩種變化檢測策略。Default是Angular默認的變化檢測策略,也就是上述提到的髒檢查,只要有值發生變化,就所有從父組件到全部子組件進行檢查,。另外一種更加高效的變化檢測方式:OnPush。OnPush策略,就是隻有當輸入數據(即@Input)的引用發生變化或者有事件觸發時,組件才進行變化檢測。

defalut 策略 main.component.ts

@Component({ selector: 'app-root', template: `

變動檢測策略

{{ slogan }}

`, }) export class AppComponent { slogan: string = 'change detection'; title: string = 'default 策略'; star: Star = new Star('周', '杰倫'); changeStar() { this.star.firstName = '吳'; this.star.lastName = '彥祖'; } changeStarObject() { this.star = new Star('劉', '德華'); }

} movie.component.ts

@Component({ selector: 'movie', styles: ['div {border: 1px solid black}'], template: `

{{ title }}

{{star.firstName}} {{star.lastName}}

`,

}) export class MovieComponent { @Input() title: string; @Input() star;

} 上面代碼中, 當點擊第一個按鈕改變明星屬性時,依次對slogan, title, star三個屬性進行檢測, 此時三個屬性都沒有變化, star沒有發生變化,是由於實質上在對star檢測時只檢測star自己的引用值是否發生了改變,改變star的屬性值並未改變star自己的引用,所以是沒有發生變化。

而當咱們點擊第二個按鈕改變明星對象時 ,從新new了一個 star ,這時變化檢測纔會檢測到 star發生了改變。

而後變化檢測進入到子組件中,檢測到star.firstName和star.lastName發生了變化, 而後更新視圖.

OnPush策略 與上面代碼相比, 只在movie.component.ts中的@component中增長了一行代碼:

changeDetection:ChangeDetectionStrategy.OnPush 此時, 當點擊第一個按鈕時, 檢測到star沒有發生變化, ok,變化檢測到此結束, 不會進入到子組件中, 視圖不會發生變化.

當點擊第二個按鈕時,檢測到star發生了變化, 而後變化檢測進入到子組件中,檢測到star.firstName和star.lastName發生了變化, 而後更新視圖.

因此,當你使用了OnPush檢測機制時,在修改一個綁定值的屬性時,要確保同時修改到了綁定值自己的引用。可是每次須要改變屬性值的時候去new一個新的對象會很麻煩,immutable.js 你值得擁有!

變化檢測對象引用 經過引用變化檢測對象ChangeDetectorRef,能夠手動去操做變化檢測。咱們能夠在組件中的經過依賴注入的方式來獲取該對象:

constructor( private changeRef:ChangeDetectorRef ){} 變化檢測對象提供的方法有如下幾種:

markForCheck() - 在組件的 metadata 中若是設置了 changeDetection:ChangeDetectionStrategy.OnPush 條件,那麼變化檢測不會再次執行,除非手動調用該方法, 該方法的意思是在變化監測時必須檢測該組件。 detach() - 從變化檢測樹中分離變化檢測器,該組件的變化檢測器將再也不執行變化檢測,除非手動調用 reattach() 方法。 reattach() - 從新添加已分離的變化檢測器,使得該組件及其子組件都能執行變化檢測 detectChanges() - 從該組件到各個子組件執行一次變化檢測 OnPush策略下手動發起變化檢測 組件中添加事件改變輸入屬性

在上面代碼movie.component.ts中修改以下

@Component({ selector: 'movie', styles: ['div {border: 1px solid black}'], template: `

{{ title }}

{{star.firstName}} {{star.lastName}}

`, changeDetection:ChangeDetectionStrategy.OnPush }) export class MovieComponent { constructor( private changeRef:ChangeDetectorRef ){} @Input() title: string; @Input() star;

changeStar(){ this.star.lastName = 'xjl'; } } 此時點擊按鈕切換名字時,star更改以下

![圖片描述][3] 第二種就是上面講到的使用變化檢測對象中的 markForCheck()方法.

ngOnInit() { setInterval(() => { this.star.lastName = 'xjl'; this.changeRef.markForCheck(); }, 1000); } 輸入屬性爲Observable 修改app.component.ts

@Component({ selector: 'app-root', template: `

變動檢測策略

{{ slogan }}

`, }) export class AppComponent implements OnInit{ slogan: string = 'change detection'; title: string = 'OnPush 策略'; star: Star = new Star('周', '杰倫'); count:Observable
相關文章
相關標籤/搜索