iis服务器助手广告
返回顶部
首页 > 资讯 > 精选 >Angular中变更检测的示例分析
  • 225
分享到

Angular中变更检测的示例分析

2023-06-14 11:06:47 225人浏览 独家记忆
摘要

这篇文章主要介绍angular中变更检测的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!核心概念-视图ViewAngular的文档中通篇都提到了一个Angular应用是一个组件树。但是Angular底层其实使

这篇文章主要介绍angular中变更检测的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

核心概念-视图View


Angular的文档中通篇都提到了一个Angular应用是一个组件树。但是Angular底层其实使用了一个低级抽象-视图View。视图View和组件之间的关系很直接-一个视图与一个组件相关联,反之亦然。每个视图都在它的component属性中保持了一个与之关联的组件实例的引用。所有的类似于属性检测、DOM更新之类的操作都是在视图上进行的。因此,技术上而言把Angular应用描述成一个视图树更加准确,因为组件是视图的一个高阶描述。在源码中有关视图是这么描述的:

A View is a fundamental building block of the application UI. It is the smallest grouping of Elements which are created and destroyed together.

视图是组成应用界面的最小单元,它是一系列元素的组合,一起被创建,一起被销毁。

Properties of elements in a View can change, but the structure (number and order) of elements in a View cannot. Changing the structure of Elements can only be done by inserting, moving or removing nested Views via a ViewContainerRef. Each View can contain many View Containers.

视图中元素的属性可以发生变化,但是视图中元素的数量和顺序不能变化。如果想要改变的话,需要通过VireContainerRef来执行插入,移动和删除操作。每个视图都会包括多个View Container。

在这篇文章中,组件和组件视图的概念是互相可替代的。

需要注意的是:网络上很多文章都把我们这里所描述的视图作为了变更检测对象或者ChangeDetectorRef。事实上,Angular中并没有一个单独的对象用来做变更检测,所有的变更检测都在视图上直接运行。

export interface ViewData {  def: ViewDefinition;  root: RootData;  renderer: Renderer2;  // index of component provider / anchor.  parentnodeDef: NodeDef|null;  parent: ViewData|null;  viewContainerParent: ViewData|null;  component: any;  context: any;  // Attention: Never loop over this, as this will  // create a polymorphic usage site.  // Instead: Always loop over ViewDefinition.nodes,  // and call the right accessor (e.g. `elementData`) based on  // the NodeType.  nodes: {[key: number]: NodeData};  state: ViewState;  oldValues: any[];  disposables: DisposableFn[]|null;}

视图的状态


每个视图都有自己的状态,基于这些状态的值,Angular会决定是否对这个视图和他所有的子视图运行变更检测。视图有很多状态值,但是在这篇文章中,下面四个状态值最为重要:

// Bitmask of statesexport const enum ViewState {  FirstCheck = 1 << 0,  ChecksEnabled = 1 << 1,  Errored = 1 << 2,  Destroyed = 1 << 3}

如果CheckedEnabled值为false或者视图处于Errored或者Destroyed状态时,这个视图的变更检测就不会执行。默认情况下,所有视图初始化时都会带上CheckEnabled,除非使用了ChangeDetectionStrategy.onPush。有关onPush我们稍后再讲。这些状态也可以被合并使用,比如一个视图可以同时有FirstCheck和CheckEnabled两个成员。

针对操作视图,Angular中有一些封装出的高级概念,详见这里。一个概念是ViewRef。他的_view属性囊括了组件视图,同时它还有一个方法detectChanges。当一个异步事件触发时,Angular从他的最顶层的ViewRef开始触发变更检测,然后对子视图继续进行变更检测。

ChangeDectionRef可以被注入到组件的构造函数中。这个类的定义如下:

export declare abstract class ChangeDetectorRef {    abstract checkNoChanges(): void;    abstract detach(): void;    abstract detectChanges(): void;    abstract markForCheck(): void;    abstract reattach(): void;}export abstract class ViewRef extends ChangeDetectorRef {        abstract destroy(): void;    abstract get destroyed(): boolean;    abstract onDestroy(callback: Function): any}

变更检测操作


负责对视图运行变更检测的主要逻辑属于checkAndUpdateView方法。他的大部分功能都是对子组件视图进行操作。从宿主组件开始,这个方法被递归调用作用于每一个组件。这意味着当递归树展开时,在下一次调用这个方法时子组件会成为父组件。

当在某个特定视图上开始触发这个方法时,以下操作会依次发生:

  • 如果这是视图的第一次检测,将ViewState.firstCheck设置为true,否则为false;

  • 检查并更新子组件/指令的输入属性-checkAndUpdateDirectiveInline

  • 更新子视图的变更检测状态(属于变更检测策略实现的一部分)

  • 对内嵌视图运行变更检测(重复列表中的步骤)

  • 如果绑定的值发生变化,调用子组件的onChanges生命周期钩子;

  • 调用子组件的OnInit和DoCheck两个生命周期钩子(OnInit只在第一次变更检测时调用)

  • 在子组件视图上更新ContentChildren列表-checkAndUpdateQuery

  • 调用子组件的AfterContentInit和AfterContentChecked(前者只在第一次检测时调用)-callProviderLifecycles

  • 如果当前视图组件上的属性发生变化,更新DOM

  • 对子视图执行变更检测-callViewAction

  • 更新当前视图组件的ViewChildren列表-checkAndUpdateQuery

  • 调用子组件的AfterViewInit和AfterViewChecked-callProviderLifecycles

  • 对当前视图禁用检测

在以上操作中有几点需要注意

深入这些操作的含义


假设我们现在有一棵组件树:

在上面的讲解中我们得知了每个组件都和一个组件视图相关联。每个视图都使用ViewState.checksEnabled初始化了。这意味着当Angular开始变更检测时,整棵组件树上的所有组件都会被检测;

假设此时我们需要禁用AComponent和它的子组件的变更检测,我们只要将它的ViewState.checksEnabled设置为false就行。这听起来很容易,但是改变state的值是一个很底层的操作,因此Angular在视图上提供了很多方法。通过ChangeDetectorRef每个组件可以获得与之关联的视图。

class ChangeDetectorRef {  markForCheck() : void  detach() : void  reattach() : void    detectChanges() : void  checkNoChanges() : void}

detach

这个方法简单的禁止了对当前视图的检测;

detach(): void {    this._view.state &= ~ViewState.checksEnabled;}

在组件中的使用方法:

export class AComponent {    constructor(        private cd: ChangeDectectorRef,    ) {        this.cd.detach();    }}

这样就会导致在接下来的变更检测中AComponent及子组件都会被跳过。

这里有两点需要注意:

  • 虽然我们只修改了AComponent的state值,但是他的子组件也不会被执行变更检测;

  • 由于AComponent及其子组件不会有变更检测,因此他们的DOM也不会有任何更新

下面是一个简单示例,点击按钮后在输入框中修改就再也不会引起下面的p标签的变化,外部父组件传递进来的值发生变化也不会触发变更检测:

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';@Component({    selector: 'app-change-dection',    template: `    <input [(ngModel)]="name">    <button (click)="stopCheck()">停止检测</button>    <p>{{name}}</p>    `,    styleUrls: ['./change-dection.component.CSS']})export class ChangeDectionComponent implements OnInit {    name = 'erik';    constructor(        private cd: ChangeDetectorRef,    ) { }    nGonInit() {    }    stopCheck() {        this.cd.detach();    }}

reattach

文章第一部分提到:如果AComponent的输入属性aProp发生变化,OnChanges生命周期钩子仍会被调用,这意味着一旦我们得知输入属性发生变化,我们可以激活当前组件的变更检测并在下一个tick中继续detach变更检测。

reattach(): void {     this._view.state |= ViewState.ChecksEnabled; }
export class ChangeDectionComponent implements OnInit, OnChanges {    @Input() aProp: string;    name = 'erik';    constructor(        private cd: ChangeDetectorRef,    ) { }    ngOnInit() {    }    ngOnChanges(change) {        this.cd.reattach();        setTimeout(() => {            this.cd.detach();        });    }}

上面这种做法几乎与将ChangeDetectionStrategy改为OnPush是等效的。他们都在第一轮变更检测后禁用了检测,当父组件向子组件传值发生变化时激活变更检测,然后又禁用变更检测。

需要注意的是,在这种情况下,只有被禁用检测分支最顶层组件的OnChanges钩子才会被触发,并不是这个分支的所有组件的OnChanges都会被触发,原因也很简单,被禁用检测的这个分支内不存在了变更检测,自然内部也不会向子元素变更所传递的值,但是顶层的元素仍可以接受到外部变更的输入属性。

译注:其实将retach()和detach()放在ngOnChanges()和OnPush策略还是不一样的,OnPush策略的确是只有在input值的引用发生变化时才出发变更检测,这一点是正确的,但是OnPush策略本身并不影响组件内部的值的变化引起的变更检测,而上例中组件内部的变更检测也会被禁用。如果将这段逻辑放在ngDoCheck()中才更正确一点。

maskForCheck

上面的reattach()方法可以对当前组件开启变更检测,然而如果这个组件的父组件或者更上层的组件的变更检测仍被禁用,用reattach()后是没有任何作用的。这意味着reattach()方法只对被禁用检测分支的最顶层组件有意义。

因此我们需要一个方法,可以将当前元素及所有祖先元素直到根元素的变更检测都开启。ChangeDetectorRef提供了markForCheck方法:

let currView: ViewData|null = view;while (currView) {  if (currView.def.flags & ViewFlags.OnPush) {    currView.state |= ViewState.ChecksEnabled;  }  currView = currView.viewContainerParent || currView.parent;}

在这个实现中,它简单的向上迭代并启用对所有直到根组件的祖先组件的检查。

这个方法在什么时候有用呢?禁用变更检测策略之后,ngDoCheck生命周期还是会像ngOnChanges一样被触发。当然,跟OnChanges一样,DoCheck也只会在禁用检测分支的顶部组件上被调用。但是我们就可以利用这个生命周期钩子来实现自己的业务逻辑和将这个组件标记为可以进行一轮变更检测。

由于Angular只检测对象引用,我们需要通过对对象的某些属性来进行这种脏检查:

// 这里如果外部items变化为改变引用位置,此组件是不会执行变更检测的// 但是如果在DoCheck()钩子中调用markForCheck// 由于OnPush策略不影响DoCheck的执行,这样就可以侦测到这个变更Component({   ...,   changeDetection: ChangeDetectionStrategy.OnPush})MyComponent {    @Input() items;    prevLength;    constructor(cd: ChangeDetectorRef) {}    ngOnInit() {        this.prevLength = this.items.length;    }    ngDoCheck() {        // 通过比较前后的数组长度        if (this.items.length !== this.prevLength) {            this.cd.markForCheck();             this.prevLenght = this.items.length;        }    }}

detectChanges

Angular提供了一个方法detectChanges,对当前组件和所有子组件运行一轮变更检测。这个方法会无视组件的ViewState,也就是说这个方法不会改变组件的变更检测策略,组件仍会维持原有的会被检测或不会被检测状态。

export class AComponent {  @Input() inputAProp;  constructor(public cd: ChangeDetectorRef) {    this.cd.detach();  }  ngOnChanges(values) {    this.cd.detectChanges();  }}

通过这个方法我们可以实现一个类似Angular.js的手动调用脏检查。

checkNoChanges

这个方法是用来当前变更检测没有产生任何变化。他执行了文章第一部分1,7,8三个操作,并在发现有变更导致DOM需要更新时抛出异常。

以上是“Angular中变更检测的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网精选频道!

--结束END--

本文标题: Angular中变更检测的示例分析

本文链接: https://www.lsjlt.com/news/270325.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Angular中变更检测的示例分析
    这篇文章主要介绍Angular中变更检测的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!核心概念-视图ViewAngular的文档中通篇都提到了一个Angular应用是一个组件树。但是Angular底层其实使...
    99+
    2023-06-14
  • Angular中的变更实例检测分析
    本篇内容介绍了“Angular中的变更实例检测分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Angul...
    99+
    2024-04-02
  • Angular中变化检测的示例分析
    这篇文章主要为大家展示了“Angular中变化检测的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Angular中变化检测的示例分析”这篇文章吧。Cha...
    99+
    2024-04-02
  • Angular中的变化检测实例分析
    这篇文章主要介绍“Angular中的变化检测实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Angular中的变化检测实例分析”文章能帮助大家解决问题。变化检...
    99+
    2024-04-02
  • Angular2之ng中变更检测问题的示例分析
    这篇文章主要介绍Angular2之ng中变更检测问题的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!开发中遇到的问题在开发中遇到一个这样的问题,代码不便透露,这里用简单的例子...
    99+
    2024-04-02
  • 浅析Angular变更检测中的DOM更新机制
    变更检测是Angular中很重要的一部分,也就是模型和视图之间保持同步。在日常开发过程中,我们无需了解变更检测,因为Angular都帮我们完成了这一部分工作,让开发人员更加专注于业务实现,提高开发效率和开发体验。但是如果想要深入使用框架,或...
    99+
    2023-05-14
    DOM更新机制 变更检测 前端 Angular.js
  • Angular变更检测的方法
    这篇文章主要讲解了“Angular变更检测的方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Angular变更检测的方法”吧!Angular 中的变更检测是一种用来将应用程序 UI 的状态...
    99+
    2023-06-29
  • Angular中如何实现变更检测
    小编给大家分享一下Angular中如何实现变更检测,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、Angular 的 DOM ...
    99+
    2024-04-02
  • 浅析Angular变更检测中的订阅异步事件
    在上一篇文章中,我们介绍了具体什么是变更检测,用一个原生JS例子来更好的去理解变更检测,以及介绍了在哪些场景下会触发变更检测。前文中总结了5种工作中常见的场景,但是我们需要先思考一下,Angular的变更检测是否支持所有的异步事件呢?如果支...
    99+
    2023-05-14
    订阅异步事件 Angular 变更检测
  • Angular中单元测试的示例分析
    这篇文章给大家分享的是有关Angular中单元测试的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。第一个测试用例当创建Angular应用后,在package.json文件...
    99+
    2024-04-02
  • Angular中什么是变更检测?什么情况下会引起变更检测?
    Angular中什么是变更检测?下面本篇文章带大家了解一下变更检测,并介绍一下什么情况下会引起变更检测,希望对大家有所帮助!什么是变更检测?简单来说,变更检测就是Angular用来检测视图与模型之间绑定的值是否发生了改变,当检测到模型中的值...
    99+
    2023-05-14
    Angular 变更检测
  • Angular中的onPush变更检测策略有哪些
    这篇文章给大家介绍Angular中的onPush变更检测策略有哪些,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。默认的变更检测策略默认情况下,Angular使用ChangeDetect...
    99+
    2024-04-02
  • Angular变更检测中的DOM更新机制是什么
    这篇文章主要介绍“Angular变更检测中的DOM更新机制是什么”,在日常操作中,相信很多人在Angular变更检测中的DOM更新机制是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Angular变更检测...
    99+
    2023-07-04
  • angular变更检测机制是什么
    Angular的变更检测机制是通过比较当前视图和上一次视图的状态来确定是否需要更新视图。它基于Zone.js库,通过Zone来跟踪和...
    99+
    2023-10-24
    angular
  • Angular变更检测是怎么引起的
    本篇内容介绍了“Angular变更检测是怎么引起的”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!什么是变更检测?简单来说,变更检测就是Ang...
    99+
    2023-07-04
  • Angular DOM中更新机制的示例分析
    这篇文章主要介绍了Angular DOM中更新机制的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。由模型变化触发的 DOM 更新是所有前端框架的重要功能(注:即保持 ...
    99+
    2023-06-15
  • Angular4中脏值检测的示例分析
    这篇文章将为大家详细讲解有关Angular4中脏值检测的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。SummaryAngular 4的脏值检测是个老话题了,而理...
    99+
    2024-04-02
  • 深入浅出讲解Angular变更检测
    Angular 中的变更检测是一种用来将应用程序 UI 的状态与数据的状态同步的机制。当应用逻辑更改组件数据时,绑定到视图中 DOM 属性上的值也要随之更改。变更检测器负责更新视图以...
    99+
    2024-04-02
  • Angular中PIPE的示例分析
    这篇文章主要为大家展示了“Angular中PIPE的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Angular中PIPE的示例分析”这篇文章吧。 ...
    99+
    2024-04-02
  • Angular中NgModule的示例分析
    这篇文章主要介绍了Angular中NgModule的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。本篇文章带大家详细了解一下Angular中的NgModule(模块)...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作