Angular | 利用 `ChangeDetectorRef` 解決 Angular 動態顯示輸入框的聚焦問題

在 Angular 應用開發中,實現用戶點擊按鈕后,原地切換顯示一個輸入框并自動獲取焦點的功能,是一個常見的交互模式。例如,搜索圖標點擊后變為搜索框,用戶可以直接輸入。然而,由于 Angular 的變更檢測和 DOM 更新機制的異步性,直接在改變顯示狀態后立即調用元素的 focus() 方法,往往會因為元素尚未完全渲染或準備就緒而失敗。

本文將探討這一問題,并介紹如何利用 ChangeDetectorRef 來更同步地更新視圖,從而實現對動態出現元素的精確聚焦。

問題再現:按鈕到輸入框的切換與聚焦

考慮以下 Angular 模板結構:

<main class="columns-content-area" *ngIf="DictManagerStack.empty() || DictManagerStack.exists('EntriesManagement')"><div class="columns-content-header"><h1 class="columns-content-title">{{ 'EntriesManagement' | translate }}</h1><button style="margin-left: auto; margin-right: 0.5rem;" *ngIf="!isClickGlassInDictManager"(click)="onDictManagerButtonClick('SearchButton', 'search')"class="normal-toolbar-button"><i class="fa-solid fa-magnifying-glass"></i></button><input #searchInput *ngIf="isClickGlassInDictManager" style="margin-left: auto; margin-right: 0.5rem; border: 1px solid #ccc; border-radius: 4px; padding: 1px;"(keyup.enter)="onDictManagerButtonClick('SearchButton', 'EnterSearch')" type="text"(keyup.esc)="onDictManagerButtonClick('SearchButton', 'cancelSearch')"(focusout)="isClickGlassInDictManager = false"[(ngModel)]="searchWordInDictManager" placeholder="搜索"/></div><p class="columns-content-description">{{ 'EntriesManagementDescription' | translate }}</p></main>

我們希望當點擊搜索按鈕時,isClickGlassInDictManager 變量變為 true,導致按鈕隱藏,輸入框顯示。同時,我們希望新出現的輸入框立即獲得焦點。

一個直觀的想法可能是在處理按鈕點擊的方法中直接改變變量并調用聚焦:

import { Component, ViewChild, ElementRef } from '@angular/core';// ... other imports@Component({ /* ... */ })
export class YourComponent {isClickGlassInDictManager = false;// 使用 @ViewChild 獲取輸入框的引用@ViewChild('searchInput') searchInputElement!: ElementRef;onDictManagerButtonClick(itemType: 'SearchButton' | 'EntriesManagementContent', item: any) {if (itemType === 'SearchButton') {this.isClickGlassInDictManager = !this.isClickGlassInDictManager;// 問題所在:此時輸入框可能還未完全呈現在 DOM 中或未準備好if (this.isClickGlassInDictManager && this.searchInputElement) {const searchInput = this.searchInputElement.nativeElement as HTMLInputElement;searchInput.focus(); // 可能失敗}}}
}

之所以會失敗,是因為 Angular 的變更檢測通常不會在你的事件處理函數執行的 同一刻 立即更新 DOM。當 isClickGlassInDictManager 的值改變時,Angular 會安排一次視圖更新,但這個更新過程可能發生在當前 JavaScript 任務完成之后。因此,在 focus() 被調用時,@ViewChild('searchInput') 對應的元素可能還不存在于 DOM 中,或者雖然存在,但瀏覽器還沒有完成其布局和渲染,導致 focus() 方法沒有效果。

解決方案:手動觸發變更檢測 cdr.detectChanges()

為了解決這個問題,我們可以利用 Angular 提供的 ChangeDetectorRef 服務來手動觸發一次變更檢測,強制 Angular 立即更新視圖,從而確保輸入框在調用 focus() 之前已經出現在 DOM 中。

以下是使用 ChangeDetectorRef 的解決方案:

import { Component, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';// ... other imports@Component({ /* ... */ })
export class YourComponent {isClickGlassInDictManager = false;@ViewChild('searchInput') searchInputElement!: ElementRef;constructor(private cdr: ChangeDetectorRef) {} // 注入 ChangeDetectorRefonDictManagerButtonClick(itemType: 'SearchButton' | 'EntriesManagementContent', item: any) {if (itemType === 'SearchButton') {// 1. 改變狀態,隱藏按鈕,準備顯示輸入框this.isClickGlassInDictManager = !this.isClickGlassInDictManager;// 2. 手動觸發變更檢測// 這會強制 Angular 立即根據 isClickGlassInDictManager 的新值更新 DOMthis.cdr.detectChanges();// 3. 在 DOM 更新后,嘗試聚焦輸入框// 此時,由于 detectChanges() 已經執行,@ViewChild 應該已經獲取到新創建的元素引用if (this.isClickGlassInDictManager && this.searchInputElement) {const searchInput = this.searchInputElement.nativeElement as HTMLInputElement;searchInput.focus(); // 現在聚焦操作應該能夠成功}}}
}

方案解釋

  1. this.isClickGlassInDictManager = !this.isClickGlassInDictManager;: 這一步改變組件狀態,指示輸入框應該顯示(如果之前是隱藏的)。
  2. this.cdr.detectChanges();: 這是關鍵步驟。它告訴 Angular 立即執行一次變更檢測。Angular 會檢查所有綁定,發現 isClickGlassInDictManager 的變化,并根據 *ngIf="isClickGlassInDictManager" 的條件,同步地在 DOM 中創建并插入搜索輸入框元素。
  3. if (this.isClickGlassInDictManager && this.searchInputElement): 在 detectChanges() 執行后,@ViewChild('searchInput') 應該已經成功獲取到了新創建的輸入框元素的引用。這個條件確保只有當輸入框確實應該顯示且引用可用時,才執行聚焦操作。
  4. searchInput.focus();: 由于 detectChanges() 已經保證了輸入框元素的存在,這里的 focus() 調用現在能夠成功地作用于實際的 DOM 元素,使其獲得焦點。

通過 cdr.detectChanges(),我們將原本可能稍后發生的 DOM 更新提前到當前方法的執行流程中,從而解決了狀態改變與 DOM 準備好進行交互之間的時序不同步問題。

總結

利用 ChangeDetectorRefdetectChanges() 方法,我們可以強制 Angular 立即更新視圖,確保目標元素在 DOM 中存在且可供操作,從而實現對動態出現元素的精確控制,例如自動聚焦。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/82830.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/82830.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/82830.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CSP認證準備第三天-差分及第36次CCF認證(BFS)

基礎知識參考&#xff1a; csp突擊前兩題常用算法代碼_ccf csp常用優化算法-CSDN博客 差分 什么是差分數組&#xff1f; 差分數組是原數組相鄰元素之間的差值構成的數組。對于原數組 a&#xff0c;其差分數組 b 定義為&#xff1a; b[1] a[1] (假設 a[0] 0) b[i] a[i] …

[案例四] 智能填寫屬性工具(支持裝配組件還有建模實體屬性的批量創建、編輯)

論文盲審結果要出來了,渣渣超沒有心情繼續寫了,過一段時間再說吧,今天宣布五一結束,哈哈哈。寫完這篇博客開始搞科研了,有時間再進NX開發學習。本次案例主要是對上次導出自動導出BOM的一個前處理,要想導出屬性,首先的有屬性。于是本著學習的態度進行制作,可能有些功能有…

四核RK3566多媒體控制板技術分享(RK3566如何實現7個串口同時進行)

四核RK3566多媒體控制板技術分享: 今天分享一款近期接觸到的四核RK3566多媒體控制板&#xff08;產品型號&#xff1a;ZK-R36A&#xff09;&#xff0c;這款產品在工業控制和智能設備領域有不錯的表現&#xff0c;特此整理了一些技術參數供大家參考。 產品概述: 這款控制板采用…

多線程代碼案例-1 單例模式

單例模式 單例模式是開發中常見的設計模式。 設計模式&#xff0c;是我們在編寫代碼時候的一種軟性的規定&#xff0c;也就是說&#xff0c;我們遵守了設計模式&#xff0c;代碼的下限就有了一定的保證。設計模式有很多種&#xff0c;在不同的語言中&#xff0c;也有不同的設計…

【計算機組成原理】第二部分 存儲器--分類、層次結構

文章目錄 分類&層次結構0x01 分類按存儲介質分類按存取方式分類按在計算機中的作用分類 0x02 層次結構 分類&層次結構 0x01 分類 按存儲介質分類 半導體存儲器磁表面存儲器磁芯存儲器光盤存儲器 按存取方式分類 存取時間與物理地址無關&#xff08;隨機訪問&#…

迅為RK3588開發板安卓GPIO調用APP運行測試

將網盤上的安卓工程文件復制到 Windows 電腦上。確保工程路徑中使用英文字符&#xff0c;不包含中文。接著&#xff0c;啟動 Android Studio&#xff0c;點擊“Open”按鈕選擇應用工程文件夾&#xff0c;然后點擊“OK”。由于下載 Gradle 和各種 Jar 包可能需要一段時間&#x…

BFS算法篇——打開智慧之門,BFS算法在拓撲排序中的詩意探索(下)

文章目錄 引言一、課程表1.1 題目鏈接&#xff1a;https://leetcode.cn/problems/course-schedule/description/1.2 題目分析&#xff1a;1.3 思路講解&#xff1a;1.4 代碼實現&#xff1a; 二、課程表||2.1 題目鏈接&#xff1a;https://leetcode.cn/problems/course-schedul…

計數循環java

import java.util.Scanner;public class Hello {public static void main(String[] args) {Scanner in new Scanner(System.in);int count 10;while(count > 0) {count count -1;System.out.println(count);}System.out.println(count);System.out.println("發射&am…

11. CSS從基礎樣式到盒模型與形狀繪制

在前端開發中&#xff0c;CSS&#xff08;層疊樣式表&#xff09;是控制網頁樣式和布局的核心技術。整理了關于 CSS 基礎樣式、文本樣式、盒模型以及形狀繪制的一些心得。以下是詳細的學習筆記。 一、基礎樣式設置 1. 字體樣式 字體樣式是網頁視覺呈現的重要組成部分&#xf…

雙種群進化算法:動態約束處理與資源分配解決約束多目標優化問題

雙種群進化算法&#xff1a;動態約束處理與資源分配解決約束多目標優化問題 一、引言 約束多目標優化問題&#xff08;CMOPs&#xff09;在工程設計、資源分配等領域廣泛存在&#xff0c;其核心是在滿足多個約束條件的同時優化多個目標函數。傳統方法往往難以平衡約束滿足與目…

【Qt】pro工程文件轉CMakeLists文件

1、簡述 Qt6以后默認使用cmake來管理工程,之前已經一直習慣使用pro,pro的語法確實很簡單、方便。 很多項目都是cmake來管理,將它們加入到Qt項目中,cmake確實是大勢所趨。比如,最近將要開發的ROS項目,也是使用的cmake語法。 以前總結的一些Qt代碼,已經編寫成pro、pri等…

手機換地方ip地址會變化嗎?深入解析

在移動互聯網時代&#xff0c;我們經常帶著手機穿梭于不同地點&#xff0c;無論是出差旅行還是日常通勤。許多用戶都好奇&#xff1a;當手機更換使用地點時&#xff0c;IP地址會隨之改變嗎&#xff1f;本文將深入解析手機IP地址的變化機制&#xff0c;幫助您全面了解這一常見但…

【Canda】常用命令+虛擬環境創建到選擇

目錄 一、conda常用命令 二、conda 環境 2.1 創建虛擬環境 2.2 conda環境切換 2.3 查看conda環境 2.4 刪除某個conda環境 2.5 克隆環境 三、依賴包管理 3.1 安裝命令 3.2 更新包 3.3 卸載包 3.4 查看環境中所有包 3.5 查看某個包的版本信息 3.6 搜索包 四、環境…

目標檢測任務常用腳本1——將YOLO格式的數據集轉換成VOC格式的數據集

在目標檢測任務中&#xff0c;不同框架使用的標注格式各不相同。常見的框架中&#xff0c;YOLO 使用 .txt 文件進行標注&#xff0c;而 PASCAL VOC 則使用 .xml 文件。如果你需要將一個 YOLO 格式的數據集轉換為 VOC 格式以便適配其他模型&#xff0c;本文提供了一個結構清晰、…

Python作業練習2

任務簡述 if_name__main_的含義&#xff0c;why? 問題解答 在Python中&#xff0c;if __name__ __main__:是一種常見的慣用法&#xff0c;用于檢查當前模塊是否是主程序入口點。要理解其含義和用途&#xff0c;首先需要了解兩個概念&#xff1a; 1. __name__: 這是一個特…

ppy/osu構建

下載 .NET (Linux、macOS 和 Windows) | .NET dotnet還行 構建&#xff1a;f5 運行&#xff1a;dotnet run --project osu.Desktop -c Debug

NY182NY183美光固態顆粒NY186NY188

NY182NY183美光固態顆粒NY186NY188 在存儲技術的競技場上&#xff0c;美光科技&#xff08;Micron&#xff09;始終扮演著革新者的角色。其NY系列固態顆粒憑借前沿的3D NAND架構和精準的工藝控制&#xff0c;成為企業級存儲和數據中心的關鍵支柱。本文將圍繞NY182、NY183、NY1…

C++的歷史與發展

目錄 一、C 的誕生與早期發展 &#xff08;一&#xff09;C 語言的興起與局限 &#xff08;二&#xff09;C 的雛形&#xff1a;C with Classes &#xff08;三&#xff09;C 命名與早期特性豐富 二、C 的主要發展歷程 &#xff08;一&#xff09;1985 年&#xff1a;經典…

DedeCMS-Develop-5.8.1.13-referer命令注入研究分析 CVE-2024-0002

本次文章給大家帶來代碼審計漏洞挖掘的思路&#xff0c;從已知可控變量出發或從函數功能可能照成的隱患出發&#xff0c;追蹤參數調用及過濾。最終完成代碼的隱患漏洞利用過程。 代碼審計挖掘思路 首先flink.php文件的代碼執行邏輯&#xff0c;可以使用php的調試功能輔助審計 …

計算機網絡|| 常用網絡命令的作用及工作原理

1.hostname 作用&#xff1a;顯示計算機的完整計算機名的主機名部分。僅當 Internet 協議 (TCP/IP) 協議作為組件安裝在網絡的網絡適配器的屬性中時&#xff0c;此命令才可用。 2.ping 作用&#xff1a; 1.用來檢測網絡的連通情況和分析網絡速度 2.根據域名得到服務器 IP …