这篇文章主要介绍“Angular变更检测中的DOM更新机制是什么”,在日常操作中,相信很多人在Angular变更检测中的DOM更新机制是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Angular变更检测中的DOM更新机制是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧! 变更检测是Angular中很重要的一部分,也就是模型和视图之间保持同步。在日常开发过程中,我们无需了解变更检测,因为Angular都帮我们完成了这一部分工作,让开发人员更加专注于业务实现,提高开发效率和开发体验。但是如果想要深入使用框架,或者想要写出高性能的代码而不仅仅只是实现了功能,就必须要去了解变更检测,它可以帮助我们更好的理解框架,调试错误,提高性能等。我们先来看一个小例子。当我们点击按钮的时候,改变了name属性,同时DOM自动被更新成新的name值。那现在有一个问题,如果我改变name的值后,紧接着把DOM中的innerText输出出来,它会是什么值呢?
import{Component,ViewChild,ElementRef}from'@angular/core'; @Component({ selector:'my-app', templateUrl:'./app.component.html', styleUrls:['./app.component.css'] }) exportclassAppComponent{ name='Empty'; @ViewChild('textContainer')textContainer:ElementRef; normalClick():void{ this.name='HelloAngular'; console.log(this.textContainer.nativeElement.innerText); } }
你答对了吗?那这两段代码中到底发生了什么呢?如果我们用原生JS来编写这段代码,那么点击按钮后的视图肯定免费云主机、域名不会发生任何变化,而在Angular中却让视图发生了变化,那它为什么会自动把视图更新了呢?这离不开一个叫做zone.js的库,简单来说,它是对发生值改变的事件做了一些处理,这个会在后面的部分详细讲解,这里暂时知道这个就可以了。如果我不想让这个库做这些处理,Angular还为我们提供了禁用zone.js的方法。可以在main.ts中设置禁用zone.js。
import{enableProdMode}from'@angular/core'; import{platformBrowserDynamic}from'@angular/platform-browser-dynamic'; import{AppModule}from'./app/app.module'; import{environment}from'./environments/environment'; if(environment.production){ enableProdMode(); } platformBrowserDynamic().bootstrapModule(AppModule,{ ngZone:'noop' }) .catch(err=>console.error(err));
当我们禁用zone.js,视图并未发生更新。到源码里找一下视图更新的相关代码。
*/ classApplicationRef{ /**@internal*/ constructor(_zone,_injector,_exceptionHandler,_initStatus){ this._zone=_zone; this._injector=_injector; this._exceptionHandler=_exceptionHandler; this._initStatus=_initStatus; /**@internal*/ this._bootstrapListeners=[]; this._views=[]; this._runningTick=false; this._stable=true; this._destroyed=false; this._destroyListeners=[]; /** *Getalistofcomponenttypesregisteredtothisapplication. *Thislistispopulatedevenbeforethecomponentiscreated. */ this.componentTypes=[]; /** *Getalistofcomponentsregisteredtothisapplication. */ this.components=[]; this._onMicrotaskEmptySubscription=this._zone.onMicrotaskEmpty.subscribe({ next:()=>{ this._zone.run(()=>{ this.tick(); }); } }); ... } /** *Invokethismethodtoexplicitlyprocesschangedetectionanditsside-effects. * *Indevelopmentmode,`tick()`alsoperformsasecondchangedetectioncycletoensurethatno *furtherchangesaredetected.Ifadditionalchangesarepickedupduringthissecondcycle, *bindingsintheapphaveside-effectsthatcannotberesolvedinasinglechangedetection *pass. *Inthiscase,Angularthrowsanerror,sinceanAngularapplicationcanonlyhaveonechange *detectionpassduringwhichallchangedetectionmustcomplete. */ tick(){ NG_DEV_MODE&&this.warnIfDestroyed(); if(this._runningTick){ consterrorMessage=(typeofngDevMode==='undefined'||ngDevMode)? 'ApplicationRef.tickiscalledrecursively': ''; thrownewRuntimeError(101/*RuntimeErrorCode.RECURSIVE_APPLICATION_REF_TICK*/,errorMessage); } try{ this._runningTick=true; for(letviewofthis._views){ view.detectChanges(); } if(typeofngDevMode==='undefined'||ngDevMode){ for(letviewofthis._views){ view.checkNoChanges(); } } } catch(e){ //Attention:Don'trethrowasitcouldcancelsubscriptionstoObservables! this._zone.runOutsideAngular(()=>this._exceptionHandler.handleError(e)); } finally{ this._runningTick=false; } } }
大致解读一下,这个ApplicationRef是Angular整个应用的实例,在构造函数中,zone(zone库)的onMicrotaskEmpty(从名字上看是一个清空微任务的一个subject)订阅了一下。在订阅里,调用了tick(),那tick里做了什么呢?思考: 上次说了最好订阅不要放到constructor里去订阅,这里怎么这么不规范呢?当然不是,上次我们说的是Angular组件里哪些应该放constructor,哪些应该放ngOnInit里的情况。但这里,ApplicationRef人家是一个service呀,只能将初始化的代码放constructor。在tick函数里,如果发现这个tick函数正在执行,则会抛出异常,因为这个是整个应用的实例,不能递归调用。然后,遍历了所有个views,然后每个view都执行了detectChanges(),也就是执行了下变更检测,什么是变更检测,会在后面详细讲解。紧接着,如果是devMode,再次遍历所有的views,每个view执行了checkNoChanges(),检查一下有没有变化,有变化则会抛错(后面会详细说这个问题,暂时跳过)。那好了,现在也知道怎么能让它更新了,就是要调用一下ApplicationRef的tick方法。
import{Component,ViewChild,ElementRef,ApplicationRef}from'@angular/core'; @Component({ selector:'app-root', templateUrl:'./app.component.html', styleUrls:['./app.component.scss'] }) exportclassAppComponent{ name='Empty'; @ViewChild('textContainer')textContainer:ElementRef={}asany; constructor(privateapp:ApplicationRef){} normalClick():void{ this.name='HelloAngular'; console.log(this.textContainer.nativeElement.innerText); this.app.tick(); } }
果然,可以正常的更新视图了。到此,关于“Angular变更检测中的DOM更新机制是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注云技术网站,小编会继续努力为大家带来更多实用的文章!
本篇内容介绍了“es6增强的功能有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! es6增强的功能:1、解构赋值,允许按照一定的模式,从数组或对象中提取值,…