當我們使用某個總結的知識點解決了某個問題的時候,我們稱其為**證真**,即使用現實的問題來驗證了自己理論的正確性,在**證真**的過程中我們學習到了新的知識;當我們用歷史總結的某個知識點來再次嘗試解決類似問題的時候發生了預期外的錯誤,我們稱其為**證偽**,即我們使用現實的問題證明某個已形成的理論是錯誤的,此時則是我們知識的提升。所以**證偽比證真更重要**。
在3.3.6小節中我們初次接觸了`exports`關鍵字,并有如下說明:
` ② 導出配置過的RouterModule,其它模塊若引用該模塊(AppRoutingModule),則將自動引用RouterModule。`

但通過對上個小節的學習我們發現以上說法是錯誤的。因為其它模塊自動導入RouterModule的原因是由于其聲明在了`imports`,而非`exports`中。也就是說:即使我們不在app-routing.module.ts中進行`exports`聲明,app模塊仍然是相當于import了RouterModule的。按這個理論,我們嘗試刪除app-routing.module.ts中`exports`聲明的RouterModule。
app-routing.module.ts
```
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: []
})
export class AppRoutingModule {
}
```
#### 測試

測試得到如上錯誤說不認識`router-outlet`這個組件。由于剛剛刪除了`exports`中的RouterModule,所以我們能夠馬上就定位到是由于該操作造成的。當然也可以推測出`router-outlet`這個組件是屬于`RouterModule`的。那么按照前面**找誰幫忙前需要引入該服務所在的模塊**的理論,我們嘗試直接在App模塊中引入`RouterModule`試試看。
app.module.ts
```
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
FormsModule,
RouterModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
```
最終的確不報錯了。我們認為當前現象最少說明了以下以點:
* [ ] **找誰幫忙前需要引入該服務所在的模塊**的理論是正確的。
* [ ] imports進行層級依賴的理論是不完全正確的。
* [ ] exports在層級依賴中起著一定的作用。
## 官方文檔
到了這種時候,我們就可以開始嘗試使用終極的解決辦法**查閱官方文檔**了,每當這時候,我們就開始恨自己為什么當初不好好的學習英文的閱讀理解部分了。
官方文檔對exports這部分進行如下解釋:
```
此 NgModule 中聲明的一組組件、指令和管道可以在導入了本模塊的模塊下任何組件的模板中使用。 導出的這些可聲明對象就是該模塊的公共 API。
The set of components, directives, and pipes declared in this NgModule that can be used in the template of any component that is part of an NgModule that imports this NgModule. Exported declarations are the module's public API.
```
雖然angular有相當優秀的官方文檔,但有時候看英文的原文會更有韻味,更能讓我們理解其中的含意。
我們好像懂了:
* [ ] 在exports中聲明組件A后,表示其它模塊在imports本模塊后,可以在自己的模塊中使用該組件A。
* [ ] 在exports中聲明模塊A后,表示其它模塊在imports本模塊后,可以在自己的模塊中使用該模塊A中所exports的組件。
* [ ] 在imports中聲明模塊A后,表示該模塊可以使用模塊A中所exports的內容(可能是本模塊組件、也可能是聲明的其它模塊中的所有exports內容)。
按上述理論重新繪制系統邏輯圖如下:

> 上述的理論也不見得就一定是正確的。但沒有任何關系,因為我們的當前理論已經可以證真當前遇到的所有問題了,而這在學習的過程中就足夠了。
最后,按上述的理論我們刪除掉klass/klass.module.ts中的exports部分。原因是Klass模塊未被任何模塊imports,當然也就不需要任何的exports了。
klass/klass.module.ts
```
/**
* 班級模塊
*/
@NgModule({
declarations: [IndexComponent, AddComponent, EditComponent],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
RouterModule.forChild(routes)
]
})
export class KlassModule {
}
```
最后我們進行系統的測試,以保證當前的變更不對歷史的功能造成任何影響 。
# 參考文檔
| 名稱 | 鏈接 | 預計學習時長(分) |
| --- | --- | --- |
| 源碼地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step3.4.8](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step3.4.8) | - |
| exports | [https://www.angular.cn/api/core/NgModule#exports](https://www.angular.cn/api/core/NgModule#exports) | 5 |
- 序言
- 第一章:Hello World
- 第一節:Angular準備工作
- 1 Node.js
- 2 npm
- 3 WebStorm
- 第二節:Hello Angular
- 第三節:Spring Boot準備工作
- 1 JDK
- 2 MAVEN
- 3 IDEA
- 第四節:Hello Spring Boot
- 1 Spring Initializr
- 2 Hello Spring Boot!
- 3 maven國內源配置
- 4 package與import
- 第五節:Hello Spring Boot + Angular
- 1 依賴注入【前】
- 2 HttpClient獲取數據【前】
- 3 數據綁定【前】
- 4 回調函數【選學】
- 第二章 教師管理
- 第一節 數據庫初始化
- 第二節 CRUD之R查數據
- 1 原型初始化【前】
- 2 連接數據庫【后】
- 3 使用JDBC讀取數據【后】
- 4 前后臺對接
- 5 ng-if【前】
- 6 日期管道【前】
- 第三節 CRUD之C增數據
- 1 新建組件并映射路由【前】
- 2 模板驅動表單【前】
- 3 httpClient post請求【前】
- 4 保存數據【后】
- 5 組件間調用【前】
- 第四節 CRUD之U改數據
- 1 路由參數【前】
- 2 請求映射【后】
- 3 前后臺對接【前】
- 4 更新數據【前】
- 5 更新某個教師【后】
- 6 路由器鏈接【前】
- 7 觀察者模式【前】
- 第五節 CRUD之D刪數據
- 1 綁定到用戶輸入事件【前】
- 2 刪除某個教師【后】
- 第六節 代碼重構
- 1 文件夾化【前】
- 2 優化交互體驗【前】
- 3 相對與絕對地址【前】
- 第三章 班級管理
- 第一節 JPA初始化數據表
- 第二節 班級列表
- 1 新建模塊【前】
- 2 初識單元測試【前】
- 3 初始化原型【前】
- 4 面向對象【前】
- 5 測試HTTP請求【前】
- 6 測試INPUT【前】
- 7 測試BUTTON【前】
- 8 @RequestParam【后】
- 9 Repository【后】
- 10 前后臺對接【前】
- 第三節 新增班級
- 1 初始化【前】
- 2 響應式表單【前】
- 3 測試POST請求【前】
- 4 JPA插入數據【后】
- 5 單元測試【后】
- 6 惰性加載【前】
- 7 對接【前】
- 第四節 編輯班級
- 1 FormGroup【前】
- 2 x、[x]、{{x}}與(x)【前】
- 3 模擬路由服務【前】
- 4 測試間諜spy【前】
- 5 使用JPA更新數據【后】
- 6 分層開發【后】
- 7 前后臺對接
- 8 深入imports【前】
- 9 深入exports【前】
- 第五節 選擇教師組件
- 1 初始化【前】
- 2 動態數據綁定【前】
- 3 初識泛型
- 4 @Output()【前】
- 5 @Input()【前】
- 6 再識單元測試【前】
- 7 其它問題
- 第六節 刪除班級
- 1 TDD【前】
- 2 TDD【后】
- 3 前后臺對接
- 第四章 學生管理
- 第一節 引入Bootstrap【前】
- 第二節 NAV導航組件【前】
- 1 初始化
- 2 Bootstrap格式化
- 3 RouterLinkActive
- 第三節 footer組件【前】
- 第四節 歡迎界面【前】
- 第五節 新增學生
- 1 初始化【前】
- 2 選擇班級組件【前】
- 3 復用選擇組件【前】
- 4 完善功能【前】
- 5 MVC【前】
- 6 非NULL校驗【后】
- 7 唯一性校驗【后】
- 8 @PrePersist【后】
- 9 CM層開發【后】
- 10 集成測試
- 第六節 學生列表
- 1 分頁【后】
- 2 HashMap與LinkedHashMap
- 3 初識綜合查詢【后】
- 4 綜合查詢進階【后】
- 5 小試綜合查詢【后】
- 6 初始化【前】
- 7 M層【前】
- 8 單元測試與分頁【前】
- 9 單選與多選【前】
- 10 集成測試
- 第七節 編輯學生
- 1 初始化【前】
- 2 嵌套組件測試【前】
- 3 功能開發【前】
- 4 JsonPath【后】
- 5 spyOn【后】
- 6 集成測試
- 7 @Input 異步傳值【前】
- 8 值傳遞與引入傳遞
- 9 @PreUpdate【后】
- 10 表單驗證【前】
- 第八節 刪除學生
- 1 CSS選擇器【前】
- 2 confirm【前】
- 3 功能開發與測試【后】
- 4 集成測試
- 5 定制提示框【前】
- 6 引入圖標庫【前】
- 第九節 集成測試
- 第五章 登錄與注銷
- 第一節:普通登錄
- 1 原型【前】
- 2 功能設計【前】
- 3 功能設計【后】
- 4 應用登錄組件【前】
- 5 注銷【前】
- 6 保留登錄狀態【前】
- 第二節:你是誰
- 1 過濾器【后】
- 2 令牌機制【后】
- 3 裝飾器模式【后】
- 4 攔截器【前】
- 5 RxJS操作符【前】
- 6 用戶登錄與注銷【后】
- 7 個人中心【前】
- 8 攔截器【后】
- 9 集成測試
- 10 單例模式
- 第六章 課程管理
- 第一節 新增課程
- 1 初始化【前】
- 2 嵌套組件測試【前】
- 3 async管道【前】
- 4 優雅的測試【前】
- 5 功能開發【前】
- 6 實體監聽器【后】
- 7 @ManyToMany【后】
- 8 集成測試【前】
- 9 異步驗證器【前】
- 10 詳解CORS【前】
- 第二節 課程列表
- 第三節 果斷
- 1 初始化【前】
- 2 分頁組件【前】
- 2 分頁組件【前】
- 3 綜合查詢【前】
- 4 綜合查詢【后】
- 4 綜合查詢【后】
- 第節 班級列表
- 第節 教師列表
- 第節 編輯課程
- TODO返回機制【前】
- 4 彈出框組件【前】
- 5 多路由出口【前】
- 第節 刪除課程
- 第七章 權限管理
- 第一節 AOP
- 總結
- 開發規范
- 備用