angular 指定components的路径_如何手动启动 Angular 程序
Angular 官方文檔寫到,為了啟動 Angular 程序,必須在 main.ts 文件里寫上如下代碼:
platformBrowserDynamic().bootstrapModule(AppModule);這行代碼 platformBrowserDynamic() 是為了構造一個 platform,Angular 官方文檔對 platform 的定義是(譯者注:為清晰理解,platform 定義不翻譯):
the entry point for Angular on a web page. Each page has exactly one platform, and services (such as reflection) which are common to every Angular application running on the page are bound in its scope.同時,Angular 也有 運行的程序實例(running application instance)的概念,你可以使用 ApplicationRef 標記(token)作為參數注入從而獲取其實例。上文的 platform 定義也隱含了一個 platform 可以擁有多個 application 對象,而每一個 application 對象是通過 bootstrapModule 構造出來的,構造方法就像上文 main.ts 文件中使用的那樣。所以,上文的 main.ts 文件中代碼,首先構造了一個 platform 對象和一個 application 對象。
譯者注:Platform->Application:Many Application->AppModule:bootstrapModule當 application 對象被正在構造時,Angular 會去檢查模塊 AppModule 的 bootstrap 屬性,該模塊是用來啟動程序的:
@NgModule({imports: [BrowserModule],declarations: [AppComponent],bootstrap: [AppComponent] }) export class AppModule {}bootstrap 屬性通常包含用來啟動程序的組件(譯者注:即根組件),Angular 會在 DOM 中查詢并匹配到該啟動組件的選擇器,然后實例化該啟動組件。
Angular 啟動過程隱含了你想要哪一個組件去啟動程序,但是如果啟動程序的組件是在運行時才被定義的該怎么辦呢?當你獲得該組件時,又該如何啟動程序呢?事實上這是個非常簡單的過程。
NgDoBootstrap
假設我們有 A 和 B 兩個組件,將編碼決定運行時使用哪一個組件來啟動程序,首先讓我們定義這兩個組件吧:
import { Component } from '@angular/core';@Component({selector: 'a-comp',template: `<span>I am A component</span>` }) export class AComponent {}@Component({selector: 'b-comp',template: `<span>I am B component</span>` }) export class BComponent {}然后在 AppModule 中注冊這兩個組件:
@NgModule({imports: [BrowserModule],declarations: [AComponent, BComponent],entryComponents: [AComponent, BComponent] }) export class AppModule {}注意,這里因為我們得自定義啟動程序,從而沒有在 bootstrap 屬性而是 entryComponents 屬性中注冊這兩個組件,并且通過在 entryComponents 注冊組件,Angular 編譯器(譯者注:Angular 提供了 @angular/compiler 包用來編譯我們寫的 angular 代碼,同時還提供了 @angular/compiler-cli CLI 工具)會為這兩個組件創建工廠類(譯者注:Angular Compiler 在編譯每一個組件時,會首先把該組件類轉換為對應的組件工廠類,即 a.component.ts 被編譯為 a.component.ngfactory.ts)。因為 Angular 會自動把在 bootstrap 屬性中注冊的組件自動加入入口組件列表,所以通常不需要把根組件注冊到 entryComponents 屬性中。(譯者注:即在 bootstrap 屬性中注冊的組件不需要在 entryComponents 中重復注冊)。
由于我們不知道 A 還是 B 組件會被使用,所以沒法在 index.html 中指定選擇器,所以 index.html 看起來只能這么寫(譯者注:我們不知道服務端返回的是 A 還是 B 組件信息):
<body><h1 id="status">Loading AppComponent content here ...</h1> </body>如果此時運行程序會有如下錯誤:
The module AppModule was bootstrapped, but it does not declare “@NgModule.bootstrap” components nor a “ngDoBootstrap” method. Please define one of these錯誤信息告訴我們, Angular 在向抱怨我們沒有指定具體使用哪一個組件來啟動程序,但是我們的確不能提前知道(譯者注:我們不知道服務端何時返回什么)。等會兒我們得手動在 AppModule 類中添加 ngDoBootstrap 方法來啟動程序:
export class AppModule {ngDoBootstrap(app) { } }Angular 會把 ApplicationRef 作為參數傳給 ngDoBootstrap(譯者注:參考 Angular 源碼中這一行),等會準備啟動程序時,使用 ApplicationRef 的 bootstrap 方法初始化根組件。
讓我們寫一個自定義方法 bootstrapRootComponent 來啟動根組件:
// app - reference to the running application (ApplicationRef) // name - name (selector) of the component to bootstrap function bootstrapRootComponent(app, name) {// define the possible bootstrap components // with their selectors (html host elements)// (譯者注:定義從服務端可能返回的啟動組件數組)const options = {'a-comp': AComponent,'b-comp': BComponent};// obtain reference to the DOM element that shows status// and change the status to `Loaded` //(譯者注:改變 id 為 #status 的內容)const statusElement = document.querySelector('#status');statusElement.textContent = 'Loaded';// create DOM element for the component being bootstrapped// and add it to the DOM// (譯者注:創建一個 DOM 元素)const componentElement = document.createElement(name);document.body.appendChild(componentElement);// bootstrap the application with the selected componentconst component = options[name];app.bootstrap(component); // (譯者注:使用 bootstrap() 方法啟動組件) }傳入該方法的參數是 ApplicationRef 和啟動組件的名稱,同時定義變量 options 來映射所有可能的啟動組件,并以組件選擇器作為 key,當我們從服務器中獲取所需要信息后,再根據該信息查詢是哪一個組件類。
先構建一個 fetch 方法來模擬 HTTP 請求,該請求會在 2 秒后返回 B 組件選擇器即 b-comp 字符串:
function fetch(url) {return new Promise((resolve) => {setTimeout(() => {resolve('b-comp');}, 2000);}); }現在我們擁有 bootstrap 方法來啟動組件,在 AppModule 模塊的 ngDoBootstrap 方法中使用該啟動方法吧:
export class AppModule {ngDoBootstrap(app) {fetch('url/to/fetch/component/name').then((name)=>{ this.bootstrapRootComponent(app, name)});} }這里我做了個 stackblitz demo 來驗證該解決方法。(譯者注:譯者把該作者 demo 中 angular 版本升級到最新版本 5.2.9,可以查看 angular-bootstrap-process,2 秒后會根據服務端返回信息自定義啟動 application)
在 AOT 中能工作么?
當然可以,你僅僅需要預編譯所有組件,并使用組件的工廠類來啟動程序:
import {AComponentNgFactory, BComponentNgFactory} from './components.ngfactory.ts'; @NgModule({imports: [BrowserModule],declarations: [AComponent, BComponent] }) export class AppModule {ngDoBootstrap(app) {fetch('url/to/fetch/component/name').then((name) => {this.bootstrapRootComponent(app, name);});}bootstrapRootComponent(app, name) {const options = {'a-comp': AComponentNgFactory,'b-comp': BComponentNgFactory};...記住我們不需要在 entryComponents 屬性中注冊組件,因為我們已經有了組件的工廠類了,沒必要再通過 Angular Compiler 去編譯組件獲得組件工廠類了。(譯者注:components.ngfactory.ts 是由 Angular AOT Compiler 生成的,最新 Angular 版本 在 CLI 里隱藏了該信息,在內存里臨時生成 xxx.factory.ts 文件,不像之前版本可以通過指令物理生成這中間臨時文件,保存在硬盤里。)
總結
以上是生活随笔為你收集整理的angular 指定components的路径_如何手动启动 Angular 程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python如何创建函数对列表里的元素进
- 下一篇: python官网32位下载_python