這篇文章主要介紹Angular2之ng中變更檢測(cè)問題的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
創(chuàng)新互聯(lián)公司公司2013年成立,先為華容等服務(wù)建站,華容等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為華容企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。開發(fā)中遇到的問題
在開發(fā)中遇到一個(gè)這樣的問題,代碼不便透露,這里用簡(jiǎn)單的例子還原一下問題所在:
有三個(gè)組件,第一個(gè)是用來展示Todo列表的組件TodoComponent,Todo是個(gè)類,包含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; } }
第二個(gè)組件同樣是一個(gè)Todo列表展示組件TodoDataComponent ,不同的是該組件需要一個(gè)TodoComponent類型的輸入,并從TodoComponent組件中獲得需要展示的Todo數(shù)據(jù)。
@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(); } }
最后一個(gè)是應(yīng)用的根組件,根組件根據(jù)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 組件是否在頁(yè)面上展示是不確定的,在上面的例子中根組件最開始沒有渲染TodoComponent組件,最后根據(jù)loading的值將TodoComponent渲染出來。而TodoDataComponent 組件的顯示又需要一個(gè)TodoComponent 進(jìn)行初始化(跟組件通過@ViewChild(TodoComponent)
獲得),這樣造成在開發(fā)模式下出現(xiàn)以下錯(cuò)誤:template:9:16 caused by: Expression has changed after it was checked. Previous value: 'undefined'. Current value: '[object Object]'
.
該錯(cuò)誤僅在開發(fā)模式下會(huì)報(bào)告出來的,解決掉總是更好的選擇,防止在生產(chǎn)環(huán)境下出現(xiàn)問題。
問題的原因及解決辦法
這個(gè)問題是ng2中的變更檢測(cè)策略造成的,ng2并沒有智能到一有數(shù)據(jù)變更就能自動(dòng)檢測(cè)到的,執(zhí)行變更檢測(cè)的一些情況有:組件中的輸入發(fā)生變化、組件中有事件響應(yīng)、setTimeOut函數(shù)等。
這樣在上面的小例子中,@ViewChild(TodoComponent)todoComponent: TodoComponent;
從undefined到[object Object],而并沒有觸發(fā)ng的變更檢測(cè)。
解決辦法也很簡(jiǎn)單,ng支持手動(dòng)觸發(fā)變更檢測(cè),只要在適當(dāng)?shù)奈恢?,調(diào)用變更檢測(cè)即可。
在上面的例子中,解決辦法為:
從@angular/core引入AfterViewInit, ChangeDetectorRef。注入ChangeDetectorRef對(duì)象,并在聲明周期鉤子ngAfterViewInit中調(diào)用變更
constructor(private todoService:TodoService, private cdr: ChangeDetectorRef){} ngAfterViewInit(){ this.cdr.detectChanges(); }
ChangeDetectorRef
用來處理ng變更的類,可以使用它來進(jìn)行完全的手動(dòng)變更檢測(cè),主要有一下方法:
1.markForCheck()
標(biāo)記為需要進(jìn)行變更檢測(cè),官方給的一下例子,setInterval不會(huì)觸發(fā)變更檢測(cè),因此模板上的numberOfTicks 并不會(huì)發(fā)生變化。
setInterval(() => { this.numberOfTicks ++ // the following is required, otherwise the view will not be updated this.ref.markForCheck(); }, 1000);
2.detach()從變更檢測(cè)樹上分離,即該組件不會(huì)進(jìn)行自動(dòng)的變更檢測(cè),變更需要手動(dòng)進(jìn)行,使用detectChanges函數(shù)。
3.detectChanges()手動(dòng)檢測(cè)變更,當(dāng)變更檢測(cè)代價(jià)較大時(shí),可以設(shè)置為定時(shí)進(jìn)行表更檢測(cè)
ref.detach(); setInterval(() => { this.ref.detectChanges(); }, 5000);
4.checkNoChanges()
進(jìn)行變更檢測(cè),有變更時(shí)拋出異常
5.reattach()
與detach()
方法的作用相反
其他一些變更檢測(cè)知識(shí)
angular2中的每一個(gè)組件都關(guān)聯(lián)到一個(gè)變更檢測(cè)器,ChangeDetectorRef可以用來控制變更檢測(cè)器進(jìn)行檢測(cè)。
瀏覽器的以下行為可以出發(fā)檢測(cè)器進(jìn)行檢測(cè):
1.所有瀏覽器事件
2.setTimeout()
和setInterval()
3.Ajax請(qǐng)求
OnPush變更檢測(cè)模式
組件默認(rèn)使用的是Default變更檢測(cè)模式,只要組件的輸入發(fā)生變化時(shí),就會(huì)觸發(fā)檢測(cè)器的執(zhí)行。除Default模式外,還有一種OnPush變更檢測(cè)模式,使用該模式首先需要在組件聲明修飾符中添加
@Component({ selector: 'todo-list', changeDetection: ChangeDetectionStrategy.OnPush, })
聲明為OnPush變更檢測(cè)模式意味著當(dāng)組件輸入發(fā)生變化時(shí),不一定會(huì)觸發(fā)變更檢測(cè)器,只有當(dāng)該輸入的引用發(fā)生變化時(shí),檢測(cè)器才會(huì)觸發(fā)。例如在一個(gè)數(shù)組中某個(gè)下標(biāo)的值發(fā)生變化時(shí),檢測(cè)器不會(huì)觸發(fā),視圖不會(huì)更新,只有該數(shù)組引用發(fā)生變化時(shí),視圖才會(huì)更新。當(dāng)然瀏覽器事件、observable發(fā)出的事件等還是會(huì)觸發(fā)檢測(cè)器的。
以上是“Angular2之ng中變更檢測(cè)問題的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司行業(yè)資訊頻道!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)建站jinyejixie.com,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
新聞名稱:Angular2之ng中變更檢測(cè)問題的示例分析-創(chuàng)新互聯(lián)
文章轉(zhuǎn)載:http://jinyejixie.com/article46/hihhg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、營(yíng)銷型網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)公司、品牌網(wǎng)站建設(shè)、虛擬主機(jī)、網(wǎng)頁(yè)設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容