本篇文章主要的向大家介紹瞭如何手動啟動angularjs程序,這裡有手動啟動angularjs程序的詳解,現在就讓我們一起來看看angularjs程序是如何手動啟動的吧
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 the page are bound in its scope.
同時,Angular 也有運行的程式實例(running application instance)的概念,你可以使用ApplicationRef
# 標記(token)作為參數注入從而獲得其實例。上文的platform
定義也隱含了一個platform
可以擁有多個application
對象,而每一個application
物件是透過bootstrapModule
建構出來的,建構方法就像上文main.ts
檔案中所使用的。所以,上文的 main.ts
檔案中程式碼,首先建構了一個 platform
物件和一個 application
物件。
當application
物件正在建構時,Angular 會去檢查模組AppModule
的bootstrap
屬性,該模組是用來啟動程式的:
@NgModule({ imports: [BrowserModule], declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule {}
bootstrap
屬性通常包含用來啟動程式的元件(譯者註:即根元件),Angular 會在DOM 中查詢並符合到該啟動元件的選擇器,然後實例化該啟動組件。 (想看更多就到PHP中文網AngularJS開發手冊中學習)
#Angular 啟動過程隱含了你想要哪一個元件去啟動程序,但是如果啟動程式的元件是運作時才被定義的該怎麼辦呢?當你取得該元件時,又該如何啟動程式呢?事實上這是個非常簡單的過程。
假設我們有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) { } }
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 component const 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
)
当然可以,你仅仅需要预编译所有组件,并使用组件的工厂类来启动程序:
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 文件,不像之前版本可以通过指令物理生成这中间临时文件,保存在硬盘里。)
好了,本篇文章到这就结束了(想看更多就到PHP中文网AngularJS使用手册中学习),有问题的可以在下方留言提问。
以上是如何手動啟動 Angular 程式?手動啟動angularjs程式的詳細解釋的詳細內容。更多資訊請關注PHP中文網其他相關文章!