当前位置: 首页 > news >正文

Angular变更检测机制

前段时间遇到这样一个 bug,通过一个 click 事件跳转到一个新页面,新页面迟迟不加载;
经过多次测试发现,将鼠标移入某个 tab ,页面就加载出来了。

举个例子,页面内容无法加载,但是将鼠标移入下图的 消息 或者 历史 tab,页面就加载出来了。

在这里插入图片描述

正常情况下,Angular 会在 组件初始化完毕后 自动进行变更检测,并更新视图。

但有时候,你可能希望在 组件实例化后 立即执行一次变更检测,以确保视图能够及时更新。这种情况下,我们可以在构造函数之后的代码中显式调用 detectChanges() 方法。

为了在切换路由后立即进行 变更检测 并渲染新页面,在路由导航结束后,Angular 提供了一个 Router.events 事件流来监听路由导航的状态。开发者可以订阅 NavigationEnd 事件,并在回调函数中调用 detectChanges() 方法。

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';@Component({// 组件元数据
})
export class MyComponent implements OnInit {constructor(private router: Router,private cdr: ChangeDetectorRef,) {}ngOnInit() {this.router.events.subscribe(event => {if (event instanceof NavigationEnd) {this.cdr.detectChanges(); // 在路由切换完成后调用 detectChanges}});}}

如此,就实现了跳转页面视图不展示的问题。

这里,简单介绍一下 Angular 的变更检测策略,包括 默认策略OnPush 策略无策略

要关闭变更检测,可以将变更检测策略设置为 无策略ChangeDetectionStrategy.OnPush)或 手动调用 detach() 方法来分离变更检测器。

1 变更检测策略

1.1 手动分离变更检测器

使用 detach() 方法来分离变更检测器,这样组件就不再与变更检测关联。

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';@Component({selector: 'app-my-component',templateUrl: './my-component.component.html'
})
export class MyComponent implements OnInit {constructor(private cdr: ChangeDetectorRef) {}ngOnInit() {this.cdr.detach(); // 分离变更检测器}
}

在此方法中,我们需要将 ChangeDetectorRef 注入到组件中,并在 ngOnInit 生命周期钩子函数中调用 detach() 方法。这样就会分离变更检测器,从而关闭变更检测。

1.2 使用变更检测策略

将组件的变更检测策略设置为 ChangeDetectionStrategy.OnPush,这会使得组件仅在输入属性发生变化时才进行变更检测。我们可以在组件的元数据中指定变更检测策略。

import { Component, ChangeDetectionStrategy } from '@angular/core';@Component({selector: 'app-my-component',templateUrl: './my-component.component.html',changeDetection: ChangeDetectionStrategy.OnPush // 设置变更检测策略为 OnPush
})
export class MyComponent {}

使用此策略时,我们需要手动触发变更检测,例如通过注入 ChangeDetectorRef 并调用 detectChanges() 方法。

需要注意的是,关闭变更检测可能导致视图无法及时更新,因此应仔细考虑是否真正需要关闭变更检测。一般情况下,使用默认的变更检测策略并让 Angular 自动执行变更检测是推荐的做法。只有在特定的性能优化需求下才应该考虑手动关闭变更检测。

2 ChangeDetectionStrategy.OnPush 策略

这里,我们要注意,将组件的变更检测策略设置为 ChangeDetectionStrategy.OnPush,这会使得组件仅在 输入属性 发生变化时才进行变更检测。输入属性指的是通过 @Input 装饰器定义在组件上的属性。这些属性用于从父组件向子组件传递数据。

当将组件的变更检测策略设置为 ChangeDetectionStrategy.OnPush 时,组件只会在 输入属性 发生变化时才触发变更检测和重新渲染。

举个例子,MyComponent 的组件,定义了一个输入属性 data,只有每次 data 的值发生变化, Angular 才会自动触发变更检测并更新组件的视图。

import { Component, Input, ChangeDetectionStrategy } from '@angular/core';@Component({selector: 'app-my-component',template: `<div>{{ data }}</div>`,changeDetection: ChangeDetectionStrategy.OnPush // 设置变更检测策略为 OnPush
})
export class MyComponent {@Input() data: string;
}

通过将组件的变更检测策略设置为 ChangeDetectionStrategy.OnPush,我们可以确保只有父组件修改了子组件的输入属性或者父组件手动调用 markForCheck() 方法,子组件才会执行变更检测、重新渲染,如此可以提高性能并减少不必要的变更检测。

事实上,除了输入属性发生变化,组件自身的事件(例如按钮点击、定时器等),也可以触发变更检测;

注意,当只有子组件内部的变量值发生改变而没有其他触发条件满足时,ChangeDetectionStrategy.OnPush 策略下的组件不会自动触发变更检测。这意味着组件的视图不会被更新。

2.1 子组件 ngModule 值变化

这里,可能会有人提问,子组件的 ngModule 值变化,会不会触发子组件的变更检测和重新渲染。

答案是不会,ngModuleAngular 中用于定义模块的装饰器函数,它通常在应用程序的根模块中使用,并且在启动时就确定了,它的变化不会被视为触发变更检测的条件。

子组件input框的 ngModule 值发生变化时,并不能直接触发子组件的变更检测,那么 input 框中内容会发生变化吗?
input 框的 ngModule 值发生变化时,输入框中的内容仍然会根据新的值进行更新,因为这是由 ngModel 实现的。这种更新是通过 DOM 事件(如 inputchange)来触发的,而不是通过 Angular 的变更检测系统。

2.2 子组件 内部数据发生变化

这里,举一个内部数据发生变化的例子。

  • 使用 ChangeDetectionStrategy.OnPush 策略;

count 的值定时发生变化,但是页面并未更新;

import { ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';@Component({selector: 'test',templateUrl: './test.component.html',styleUrls: ['./test.component.less'],changeDetection: ChangeDetectionStrategy.OnPush,
})export class TestComponent implements OnInit, OnDestroy {constructor(private router: Router,private cdr: ChangeDetectorRef,) { }count = 1;ngOnInit(): void {setInterval(() => {this.count++;}, 1000);}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 不使用 ChangeDetectionStrategy.OnPush 策略;

页面数据会刷新

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.3 父组件传值发生变化

父组件传值,直接修改了可变对象(如:数组、对象等),而没有创建一个新的引用,那么组件可能无法检测到这个改变,从而不会触发变更检测。

items: string[] = ['Item 1', 'Item 2', 'Item 3'];
this.items.push('New Item');

3 关闭变更检测

Angular 中,我们可以通过使用 ChangeDetectorRef 来关闭或禁用变更检测。ChangeDetectorRef 是一个服务,提供了与变更检测相关的方法。以下是一种关闭变更检测的方法:

注入 ChangeDetectorRef 服务:

import { Component, ChangeDetectorRef } from '@angular/core';@Component({selector: 'app-example',template: `<!-- Your component's template -->`
})
export class ExampleComponent {constructor(private cdr: ChangeDetectorRef) {}
}

在需要关闭变更检测的地方调用 detach() 方法

this.cdr.detach();

调用 detach() 方法会将组件从变更检测树中分离,意味着该组件及其子组件将不再进行自动的变更检测和视图更新。这可以帮助减少不必要的计算和渲染,提高性能。

需要注意的是,一旦你将组件从变更检测树中分离,它将不再自动响应输入属性的变化或事件的触发。如果你需要手动控制变更检测,可以使用 markForCheck() 方法来通知 Angular 运行变更检测。例如:

this.cdr.markForCheck();

使用 markForCheck() 方法可以标记组件及其父组件,使其在下一次变更检测周期中进行变更检测。

总结起来,通过 ChangeDetectorRefdetach() 方法,我们可以关闭变更检测以提高性能,并使用 markForCheck() 方法手动触发变更检测。请注意,在大多数情况下,不需要手动关闭变更检测,Angular 的默认行为通常已经足够高效和准确。

this.cdr.markForCheck()this.cdr.detectChanges()是Angular中的变更检测相关方法,它们有一些区别和适用场景。

  • this.cdr.markForCheck(): 调用markForCheck()方法会通知 Angular 在下一次变更检测周期中检查组件及其子组件,并执行相应的变更检测操作。该方法将标记组件为“已脏”(dirty),意味着组件可能发生了变化,需要进行检查。这对于在组件中进行异步操作,但可能没有直接触发变更的情况非常有用。调用markForCheck()方法本身不会立即触发变更检测,而是等待下一次变更检测周期执行。

  • this.cdr.detectChanges(): 调用detectChanges()方法会立即触发一次变更检测,无论组件是否已被标记为“脏”。这将从组件树的根节点开始进行变更检测,并检查任何已标记为“脏”的组件。这可以用来强制立即进行变更检测,而不必等待下一次自动变更检测周期。但是,过度使用detectChanges()方法可能会导致性能问题,因为它执行了全面的变更检测,而不只是对标记为“脏”的组件进行检查。

从使用角度来看,通常情况下应该优先使用this.cdr.markForCheck()方法,因为它更高效且更符合 Angular 的变更检测机制。只有在特殊情况下,如在组件中调用了异步操作但未触发变更时,才应该使用this.cdr.detectChanges()方法来强制立即进行变更检测。

相关文章:

Angular变更检测机制

前段时间遇到这样一个 bug&#xff0c;通过一个 click 事件跳转到一个新页面&#xff0c;新页面迟迟不加载&#xff1b; 经过多次测试发现&#xff0c;将鼠标移入某个 tab &#xff0c;页面就加载出来了。 举个例子&#xff0c;页面内容无法加载&#xff0c;但是将鼠标移入下图…...

Redis之String类型

文章目录 Redis之String类型1. 赋值/获取值2. 同时设置/获取多个键值3. 数值增减4. 获取字符串长度5. 向尾部追加值6. 分布式锁7.应用场景 Redis之String类型 Redis命令不区分大小写 1. 赋值/获取值 赋值&#xff1a;set key value 取值&#xff1a;get key (当键不存在时候&…...

使用redis中的zset实现滑动窗口限流

使用redis和zset实现滑动窗口限流 文章目录 使用redis和zset实现滑动窗口限流Zset**初始化一个ZSet**&#xff1a;其中包含所有用户的ID和时间戳。**添加元素到ZSet**&#xff1a;当用户发起请求时&#xff0c;将当前时间戳和用户ID作为元素添加到ZSet中。**删除过期的元素**&a…...

Linux下C语言使用 netlink sockets与内核模块通信

netlink简介 Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口。在Linux标准内核中&#xff0c;系统默认集成了很多netlink实例&#xff0c;比如日志上报、路由系统等&#xff0c;netlink消息是双向的&a…...

excel中的引用与查找函数篇3

1、INDEX(array,row_num,[col_num])&#xff1a;获取指定范围中指定行号和列号对应的数据 index(查询范围,行号,列号) 行号和列号是相对选中查询范围来写的&#xff1a;分别把第二行第三列的数据和第四行第二列的数据查找出来。 数据是单行或单列&#xff0c;后面只需要给一个参…...

【Linux学习笔记】 - 常用指令学习及其验证(下)

前言&#xff1a;本文延续上一篇文章【Linux学习笔记】 - 常用指令学习及其验证&#xff08;上&#xff09;对常用的指令进行介绍和验证。 一、mv指令 &#xff08;1&#xff09;功能&#xff1a;用来移动文件或者将文件改名 &#xff08;2&#xff09;语法及验证&#xff1a…...

面试官:请说说flex布局_番茄出品.md

面试官&#xff1a;请说说flex布局_番茄出品.md start 依然记得当初学习 flex 布局时&#xff0c;用 flex 布局&#xff1a;画麻将。一筒到九筒&#xff0c;应有尽有。但是光和面试官说&#xff0c;我用 flex 布局画过麻将&#xff0c;并没有什么用。面试官问你一个语法&…...

ChatGLM DeepSpeed/P-Tuning v2 调参

之前尝试了基于ChatGLM-6B使用LoRA进行参数高效微调,本文给大家分享使用DeepSpeed和P-Tuning v2对ChatGLM-6B进行微调,相关代码放置在GitHub上面:llm-action。 ChatGLM-6B简介 ChatGLM-6B相关的简介请查看之前的文章,这里不再赘述。 P-Tuning v2简介 P-Tuning是一种较新…...

Leetcode每日一题:打家劫舍系列Ⅰ、Ⅱ、Ⅲ、Ⅳ(2023.9.16~2023.9.19 C++)

由于之前写过打家劫舍系列&#xff0c;这里直接弄个合集&#xff0c;后面应该还有个iv。 目录 198. 打家劫舍 213. 打家劫舍 II 337. 打家劫舍 III 2560. 打家劫舍 IV 198. 打家劫舍 题目描述&#xff1a; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都…...

容易对一个异性产生依赖感怎么办?

歌词&#xff1a;爱总让人伤心&#xff0c;但你要学会去明白~ &#x1f442; Photograph - Ed Sheeran - 单曲 - 网易云音乐 目录 &#x1f33c;前言 &#x1f61f;一、对另一个人的依赖感&#xff0c;本质是什么&#xff1f; &#x1f60a;二、如何减少对伴侣的依赖感&am…...

Windows10/11无线网卡WIFI驱动详细下载安装教程

官网下载WIFI驱动 《intel官网》 找到下载Windows 10 and Windows 11* WiFi package drivers 查看详细信息 下载对应操作系统的WIFI驱动 安装驱动&#xff0c;然后重启电脑即可。...

面向面试知识--Lottery项目

面向面试知识–Lottery项目 1.设计模式 为什么需要设计模式&#xff1f; &#xff08;设计模式是什么&#xff1f;优点有哪些&#xff1f;&#xff09; 设计模式是一套经过验证的有效的软件开发指导思想/解决方案&#xff1b;提高代码的可重用性和可维护性&#xff1b;提高团…...

SpringBoot接口中如何直接返回图片数据

SpringBoot接口中如何直接返回图片数据 目录 接口直接返回图片数据 起因 类似这种 根据个人经验 优雅的实现图片返回 接口直接返回图片数据 起因 最近在做涉及到分享推广的业务&#xff0c;需要由业务员分享二维码进入推广页面&#xff0c;由于是新项目&#xff0c;前期…...

c语言进阶部分详解(指针进阶1)

大家好&#xff01;指针的初阶内容我已经写好&#xff0c;可移步至我的文章&#xff1a;c语言进阶部分详解&#xff08;指针初阶&#xff09;_总之就是非常唔姆的博客-CSDN博客 基本内容我便不再赘述&#xff0c;直接带大家进入进阶内容&#xff1a; 目录 一.字符指针 1.讲解…...

计算机竞赛 大数据商城人流数据分析与可视化 - python 大数据分析

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的基站数据分析与可视化 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度…...

各种电机驱动原理

步进电机 步进电机参考资料 野火官方文档 步进电机驱动原理 上面参考文档中有的内容就不写了&#xff0c;写一下我自己的总结吧。 说明&#xff1a; 电机驱动器输入信号有电机转动方向信号DIR&#xff0c;电机转速信号PWM&#xff0c;电机使能信号EN&#xff1b;电机驱动器…...

人脸图像数据增强

为什么要做数据增强 在计算机视觉相关任务中&#xff0c;数据增强&#xff08;Data Augmentation&#xff09;是一种常用的技术&#xff0c;用于扩展训练数据集的多样性。它包括对原始图像进行一系列随机或有规律的变换&#xff0c;以生成新的训练样本。数据增强的主要目的是增…...

Android 查看按键信息的常用命令详解

Android 查看按键信息的常用命令详解 文章目录 Android 查看按键信息的常用命令详解一、主要命令&#xff1a;二、命令详解1、getevent2、getevent -l3、dumsys input4、cat XXX.kl4、cat /dev/input/eventX5、getevent 其他命令6、input keyevent XX 三、简单示例修改四、总结…...

【Java 基础篇】Properties 结合集合类的使用详解

Java 中的 Properties 类是一个常见的用于管理配置信息的工具&#xff0c;它可以被看作是一种键值对的集合。虽然 Properties 通常用于处理配置文件&#xff0c;但它实际上也可以作为通用的 Map 集合来使用。在本文中&#xff0c;我们将详细探讨如何使用 Properties 作为 Map 集…...

数字孪生体标准编程

数字孪生体标准 括ISO TC184/SC4正在制定数字孪生制造标准ISO 23247、ISO/IEC JTC1/AG11正在推动数字孪生体标准、IEEE P2806正在做有关“数字表达”的标准。赢家通吃的标准战 卡尔夏皮罗和哈尔范里安撰写了《信息规则&#xff1a;网络经济战略指南》&#xff08;Information R…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分&#xff1a; 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟

2025年4月29日&#xff0c;在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上&#xff0c;可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞&#xff0c;强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践

前言&#xff1a;本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中&#xff0c;跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南&#xff0c;你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案&#xff0c;并结合内网…...

python打卡第47天

昨天代码中注意力热图的部分顺移至今天 知识点回顾&#xff1a; 热力图 作业&#xff1a;对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图&#xff0c;展示模…...