您可能已經嘗試過在 app.component 的 ngOnInit 函數中執行此操作,但意識到您的數據需要更早加載。您可能還嘗試過實現解析器,但意識到它們更適合單個路由的上下文。以下是在頁面加載之前加載數據的另一種方法,您可能還不知道:APP_INITIALIZER。
定義
在深入研究代碼之前,讓我們更好地了解APP_INITIALIZER是什么以及它是如何工作的。
APP_INITIALIZER令牌允許您為應用程序提供其他初始化函數。初始化函數(您可能已經從名稱中收集到)在應用初始化期間執行。這些函數的返回類型必須是 void、Promise 或可觀察的。如果從這些函數中的任何一個返回 Promise 或可觀察量,則應用程序僅在它們完成后才初始化。
簡單來說,我喜歡把它看作是定義一個“啟動”階段,在這個階段中,你可以確保你的應用正常運行所需的所有核心數據在用戶開始與之交互之前都已加載。
以下是可以在初始化函數中加載的內容的幾個示例:
翻譯
經過身份驗證的用戶數據
配置數據
例
為簡單起見,讓我們以加載當前經過身份驗證的用戶的數據為例。
大多數 Web 應用在屏幕右上角顯示當前用戶的個人資料圖片和名稱,因此讓我們實現類似的內容。我將使用一個新的角度安裝(14.1)和引導5作為CSS:
現在打開您的并導入引導:styles.scss
如果您使用的是不同版本的Angular,則某些導入和語法可能會有所不同,因此,如果您要遵循代碼,請注意這一點。
奠定基礎
讓我們從創建一個負責提供當前用戶數據的服務開始,該服務現在將如下所示:
這將是我們數據的默認值,直到我們發出請求以獲取實際的當前用戶數據。
讓我們利用這些數據并將其顯示在屏幕的右上角。為了簡單起見,我們將直接在應用程序組件中執行此操作。
首先,我們注入我們的用戶服務:
然后對于網頁:
我強調了我們實際顯示用戶的姓名和個人資料圖片的重要部分。
現在我們已經奠定了基礎,剩下要做的就是實現一個函數來獲取實際的用戶數據,然后查看我們將在何時何地調用它。
我不打算為此使用實際的后端服務,而是在我們的資產文件夾中創建一個JSON文件,我們將在其中對數據進行硬編碼:
我們將定義負責獲取 內部數據的函數,如下所示:UserService
不要忘記導入 中的 .HttpClientModuleAppModule
實現APP_INITIALIZER
正如我們在定義部分中了解到的那樣,APP_INITIALIZER讓我們定義其他初始化函數,因此現在讓我們在單獨的文件中定義一個。
您可以根據需要命名文件和函數。我主要堅持使用更通用的名稱,因為我通常使用.如果您更喜歡以不同的方式執行,則可以命名此函數或類似名稱(因為這是它唯一執行的操作),然后創建單獨的函數來加載您可能需要的任何其他數據。forkJoinloadUserDataFactory
現在,唯一要做的就是將此函數標記為APP_INITIALIZER以便 Angular 知道在應用初始化期間執行它。為此,我們需要將以下提供程序添加到 AppModule 中的提供程序數組中:
就是這樣。如果現在刷新頁面,您應該會看到一個大約 1 秒的空白頁(由于我們在獲取 JSON 文件時添加的延遲),之后頁面將加載,并在右上角顯示實際的用戶名和頭像(在 user.json 文件中指定的用戶名和頭像)。
需要考慮的事項
可能最重要的一點是,如果從任何初始值設定項函數錯誤返回的可觀察值,則應用將不再初始化。在我們的示例中,您可以通過重命名或臨時刪除文件來查看此操作,這將導致 Observable 失敗并顯示 404 錯誤。因此,您將被困在最初的空白頁上。
若要阻止這種情況發生,請始終確保使用運算符捕獲任何潛在錯誤,并為數據提供默認值或將用戶重定向到特定的錯誤頁面,您可以在其中向他們提供出錯的詳細信息以及如何繼續前進。在我們的示例中,重定向到錯誤頁面可能如下所示 - 如果您想嘗試此操作,請不要忘記通過更新 AppModule 中提供程序的鍵來將 添加為依賴項,然后創建新頁面及其路由:user.json catchError Router deps
您看到 1 秒鐘的空白頁實際上是 .發生這種情況的原因是,由于在可觀察完成之前未初始化應用,因此不會填充該元素,因此您看不到任何內容。我通常做的是添加一個加載的圖像/文本作為元素的子級。當應用完成初始化時,你放入 其中的任何內容都將被覆蓋。我給你一個例子,你可以在下面嘗試。如果要使用它,請考慮在初始化AppFactory函數中增加可觀察量的延遲。index.html<app-root><app-root><app-root>
習慣使用 RxJS(除非你使用的是承諾),因為通常情況下,你需要使用一堆 RxJS 函數和運算符才能獲得正確的結果,是我經常在這樣的情況下使用的。例如,在我們的示例中,我們只處理了用戶登錄時的情況,但如果用戶實際上是訪客,該怎么辦?在這種情況下,我們可能希望堅持使用我們定義的默認數據。在單個流中執行此操作的一種方法看起來像這樣 - 請記住,這只是一個示例,由于我們尚未一起定義任何內容,因此在當前項目中不會開箱即用 :forkJoin iif switchMap map catchError tap authService