国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Angular2學習教程之ng中變更檢測問題詳解

2019-11-19 16:27:49
字體:
來源:轉載
供稿:網友

開發中遇到的問題

在開發中遇到一個這樣的問題,代碼不便透露,這里用簡單的例子還原一下問題所在:

有三個組件,第一個是用來展示Todo列表的組件TodoComponent,Todo是個類,包含id和name屬性。

@Component({ selector: 'todo-list', template: `  <p *ngFor='let item of todos'>{{ item.name }}</p> `,})export class TodoComponent{ @Input() todos: Todo[]; public getTodos():Todo[]{  return this.todos; }}

第二個組件同樣是一個Todo列表展示組件TodoDataComponent ,不同的是該組件需要一個TodoComponent類型的輸入,并從TodoComponent組件中獲得需要展示的Todo數據。

@Component({ selector: 'app-todo-data', template: `<p *ngFor='let item of todos'>{{ item.name }}</p>  <button (click)='getData()'>get data</button>`, styleUrls: ['./todo-data.component.css'], inputs: ['todoComponent'],})export class TodoDataComponent implements OnInit { todoComponent: TodoComponent; todos: Todo[] constructor() { } ngOnInit() { } getData(){  this.todos=this.todoComponent.getTodos(); }}

最后一個是應用的根組件,根組件根據loading值來確定是否加載TodoComponent組件,并展示TodoDataComponent 組件。

//app.component.htm<div> <div *ngIf='loading'>  <todo-list [todos]='todos'></todo-list>  <button (click)='changeall()'>next</button> </div></div><div> <app-todo-data [todoComponent]='todoComponent'></app-todo-data></div>//app.component.ts@Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'],})export class AppComponent implements OnInit { todos: Todo[]; @ViewChild(TodoComponent) todoComponent: TodoComponent; loading: boolean = true; constructor(private todoService:TodoService){  super(true); } ngOnInit(){  this.todoService.todos.subscribe(data => {this.todos=data});  this.todoService.load(0, 3); } changeall(){  this.todoService.load(3, 3); }}

這樣問題就來了,TodoComponent 組件是否在頁面上展示是不確定的,在上面的例子中根組件最開始沒有渲染TodoComponent組件,最后根據loading的值將TodoComponent渲染出來。而TodoDataComponent 組件的顯示又需要一個TodoComponent 進行初始化(跟組件通過@ViewChild(TodoComponent)獲得),這樣造成在開發模式下出現以下錯誤:
template:9:16 caused by: Expression has changed after it was checked. Previous value: 'undefined'. Current value: '[object Object]'.

該錯誤僅在開發模式下會報告出來的,解決掉總是更好的選擇,防止在生產環境下出現問題。

問題的原因及解決辦法

這個問題是ng2中的變更檢測策略造成的,ng2并沒有智能到一有數據變更就能自動檢測到的,執行變更檢測的一些情況有:組件中的輸入發生變化、組件中有事件響應、setTimeOut函數等。

這樣在上面的小例子中, @ViewChild(TodoComponent)todoComponent: TodoComponent;從undefined到[object Object],而并沒有觸發ng的變更檢測。

解決辦法也很簡單,ng支持手動觸發變更檢測,只要在適當的位置,調用變更檢測即可。
在上面的例子中,解決辦法為:

從@angular/core引入AfterViewInit, ChangeDetectorRef。注入ChangeDetectorRef對象,并在聲明周期鉤子ngAfterViewInit中調用變更

constructor(private todoService:TodoService, private cdr: ChangeDetectorRef){}ngAfterViewInit(){ this.cdr.detectChanges();}

ChangeDetectorRef

用來處理ng變更的類,可以使用它來進行完全的手動變更檢測,主要有一下方法:

1.markForCheck()標記為需要進行變更檢測,官方給的一下例子,setInterval不會觸發變更檢測,因此模板上的numberOfTicks 并不會發生變化。

setInterval(() => {this.numberOfTicks ++ // the following is required, otherwise the view will not be updated this.ref.markForCheck();}, 1000);

2.detach()從變更檢測樹上分離,即該組件不會進行自動的變更檢測,變更需要手動進行,使用detectChanges函數。

3.detectChanges()手動檢測變更,當變更檢測代價較大時,可以設置為定時進行表更檢測

ref.detach();setInterval(() => { this.ref.detectChanges();}, 5000);

4.checkNoChanges()進行變更檢測,有變更時拋出異常

5.reattach()detach()方法的作用相反

其他一些變更檢測知識

angular2中的每一個組件都關聯到一個變更檢測器,ChangeDetectorRef可以用來控制變更檢測器進行檢測。
瀏覽器的以下行為可以出發檢測器進行檢測:

1.所有瀏覽器事件

2.setTimeout()setInterval()

3.Ajax請求

OnPush變更檢測模式

組件默認使用的是Default變更檢測模式,只要組件的輸入發生變化時,就會觸發檢測器的執行。除Default模式外,還有一種OnPush變更檢測模式,使用該模式首先需要在組件聲明修飾符中添加

@Component({ selector: 'todo-list', changeDetection: ChangeDetectionStrategy.OnPush,})

聲明為OnPush變更檢測模式意味著當組件輸入發生變化時,不一定會觸發變更檢測器,只有當該輸入的引用發生變化時,檢測器才會觸發。例如在一個數組中某個下標的值發生變化時,檢測器不會觸發,視圖不會更新,只有該數組引用發生變化時,視圖才會更新。當然瀏覽器事件、observable發出的事件等還是會觸發檢測器的。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 呼图壁县| 缙云县| 西安市| 威海市| 尖扎县| 安宁市| 全州县| 黎城县| 舒城县| 府谷县| 确山县| 礼泉县| 铜鼓县| 故城县| 句容市| 托里县| 剑河县| 凌云县| 曲松县| 错那县| 曲阳县| 黄梅县| 贵南县| 博客| 洮南市| 太白县| 米脂县| 安宁市| 奎屯市| 阳高县| 桦川县| 南陵县| 桦南县| 阿拉尔市| 西乡县| 龙岩市| 浙江省| 文成县| 清远市| 射洪县| 梧州市|