Angular從普通路由到惰性載入

来源:http://www.cnblogs.com/nangxi/archive/2017/11/15/7837342.html
-Advertisement-
Play Games

這篇文章我想來集中地講述一下Angular路由的普通應用到惰性載入的知識,對我這段時間的學習做一個全面的彙總! Angular的路由,我把它的演變過程分成三個階段: 1.Angular路由直接在app.module.ts-->imports--> RouterModule裡面編寫路由; 2.由於直接 ...


這篇文章我想來集中地講述一下Angular路由的普通應用到惰性載入的知識,對我這段時間的學習做一個全面的彙總!

Angular的路由,我把它的演變過程分成三個階段:

1.Angular路由直接在app.module.ts-->imports--> RouterModule裡面編寫路由;

2.由於直接在 RouterModule裡面編寫路由不方便路由管理,會使得imports裡面的內容過於冗長,所以在app-routing.module.ts裡面,把路由的編寫代碼獨立出來;

3.當我們在做項目的時候,一個項目往往由不止一個人負責,這時候用第二種方法我們會發現,當我們最後要把每個人負責的部分整合起來的時候,要在app.module.ts裡面導入一大堆的組件,註冊一大堆的組件,這樣使得代碼編寫混亂,從而不利於其他程式員閱讀和後期的代碼修改。因此,就出現了惰性載入這種東西。

接下來我們分三個部分來解說一下路由的成長歷程。(PS:下麵所有demo的css樣式不是講述重點,這裡省略)

一、Angular路由的嬰兒時期

嬰兒時期指的是Angular路由直接在app.module.ts-->imports--> RouterModule裡面編寫路由,我們用一個例子來看一下嬰兒時期的路由。

1.demo效果

圖裡面的表格可以看出我們接下來這個demo的路由規則

2.demo目錄

----------app.comonent.ts ----------app.component.html ----------pagenot.ts ----------pagenot.html(地址錯誤顯示界面) ----------app.module.ts ----------home(文件夾) ------------home.component.ts ------------home.component.html ------------children(子路由文件夾) --------------children.component.ts --------------children.component.html ----------detail(文件夾) ------------detail.component.ts ------------detail.component.html ----------contact(文件夾) ------------contact.component.ts ------------contact.component.html ----------side-bar(文件夾) ------------sidebar.component.ts ------------sidebar.component.html

3.代碼講解

看到上面的目錄,其實才幾個組件,註冊就要一大堆,慢慢的我們就會發現惰性載入的重要性,這個是後話了。 app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
//從路由庫導入RouterModule
import { RouterModule }   from '@angular/router';
//以下是組件的導入
import { AppComponent } from './app.component';
import { HomeComponent } from  './home/home.component';
import { DetailComponent } from './detail/detail.component';
import { ContactComponent } from './contact/contact.component';
import { SidebarComponent } from './side-bar/sidebar.component';
import { ChildrenComponent } from './home/children/children.component';
import { PageNotComponent } from  './pagenot';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    DetailComponent,
    ContactComponent,
    SidebarComponent,
    ChildrenComponent,
    PageNotComponent
  ],
  imports: [
    BrowserModule,
    //定義路由規則
    RouterModule.forRoot([
      {
        path: 'home',
        component: HomeComponent,//首頁組件
        children:[{
          path: 'child',
          component: ChildrenComponent //首頁的子路由組件
        }]
      },
      {
        path: 'detail',
        component: DetailComponent  //詳情頁組件
      },
      {
        path: 'contact',
        component: ContactComponent  //聯繫方式組件
      },
      { //重定向路由
        path: '',   
        redirectTo: '/home',  //當url為空的時候,跳轉到HomeComponent組件
        pathMatch: 'full' 
      },
      { //通配符路由
        path: '**', 
        component: PageNotComponent  //頁面錯誤組件
      }

    ])
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
View Code 在這裡其實要註意的是重定向路由一定要在通配符路由之前,否則在整個URL等於''時,如果通配符路由在重定向路由之前,通配符路由會以為是地址錯誤從而顯示的是地址錯誤界面。在我們這個例子中預設路由應該只有在整個URL等於''時才重定向到HomeComponent,別忘了把重定向路由設置為pathMatch = 'full'。 app.component.html
<div class="jumbotron">
    <h1>Welcome to use Angular</h1>
      <p>...</p>
</div>
<div class="contain-wrapper">
    <sidebar></sidebar>
    <div class="result-wrapper">
        <router-outlet></router-outlet>
    </div>
</div>
View Code app.component.ts(其他的ts文件跟這個文件差不多,只是修改相對應的名字而已,每個名字對應的組件我在app.module.ts標註)
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
}
View Code pagenot.html
<div class="pagenot">
    <p>地址錯誤請重新輸入!</p>
</div>
home.component.html
<p>這是首頁</p>
<div class="home-contain">
    <button routerLink="/home/child" class="btn btn-primary">點擊這裡運用子路由</button>
    <div class="children-contain">
        <router-outlet></router-outlet>
    </div>
</div> 
children.component.html
<table class="table table-hover">
    <caption>路由</caption>
    <tr>
        <th></th>
        <th>首頁</th>
        <th>詳情</th>
        <th>聯繫方式</th>
    </tr>
    <tr>
        <td>有無子路由</td>
        <td></td>
        <td></td>
        <td></td>
    </tr>
</table>
detail.component.html
<p>這是詳情頁</p>
contact.component.html
<p>這是聯繫方式頁面</p>
sidebar.component.html
<div class="sidebar">
    <ul>
        <li><a routerLink="/home">首頁</a></li>
        <li><a routerLink="/detail">詳情</a></li>
        <li><a routerLink="/contact">聯繫方式</a></li>
    </ul>
</div>

4.總結

我們來捋一下路由使用的步驟 (1)在app.module.ts裡面導入所有組件並註冊,然後導入RouterModule,並且在imports裡面註冊,同時定義路由規則; (2)在相應的鏈接用routerLink="/路由"定義鏈接要跳轉的路由; (3)在需要的位置設置路由出口<router-outlet></router-outlet>,一個模板中只能有一個未命名的<router-outlet>。

5.小小的改進,逐漸向少年期過渡

直接在imports裡面直接定義路由規則有些不符合我們的變成習慣,我們可以將這部分獨立出來,這樣才使得每個模塊功能明確,直接修改app.module.ts文件就可以了
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
//從路由庫導入RouterModule,Routes
import { RouterModule,Routes }   from '@angular/router';
//以下是組件的導入
import { AppComponent } from './app.component';
import { HomeComponent } from  './home/home.component';
import { DetailComponent } from './detail/detail.component';
import { ContactComponent } from './contact/contact.component';
import { SidebarComponent } from './side-bar/sidebar.component';
import { ChildrenComponent } from './home/children/children.component';
import { PageNotComponent } from  './pagenot';



//定義路由規則,把這塊獨立出來
const appRoutes: Routes = [
  { path: 'home',component: HomeComponent, //首頁組件
    children:[{path: 'child',component: ChildrenComponent}]},  //首頁子路由組件
  { path: 'detail',component: DetailComponent}, //詳情頁組件
  { path: 'contact',component: ContactComponent},  //聯繫方式組件
  { path: '',redirectTo: '/home',pathMatch: 'full'},  //重定向組件
  { path: '**',component: PageNotComponent} //通配符路由組件
];


@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    DetailComponent,
    ContactComponent,
    SidebarComponent,
    ChildrenComponent,
    PageNotComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot(appRoutes)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
View Code 但是說實話,這樣的分離還不夠徹底,路由該長大了。  

二、Angular路由的少年時期

為了分工明確,後期容易管理,我們直接把路由規則用一個叫做app-routing.module.ts的文件把它獨立出來 在app.module.ts同級目錄下添加app-routing.module.ts文件 app.module.ts修改
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
//導入AppRoutingModule路由定義文件
import { AppRoutingModule } from './app-routing.module';
//以下是組件的導入
import { AppComponent } from './app.component';
import { HomeComponent } from  './home/home.component';
import { DetailComponent } from './detail/detail.component';
import { ContactComponent } from './contact/contact.component';
import { SidebarComponent } from './side-bar/sidebar.component';
import { ChildrenComponent } from './home/children/children.component';
import { PageNotComponent } from  './pagenot';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    DetailComponent,
    ContactComponent,
    SidebarComponent,
    ChildrenComponent,
    PageNotComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
View Code app-routing.module.ts
import { NgModule }             from '@angular/core';
//從路由庫導入RouterModule,Routes
import { RouterModule,Routes }   from '@angular/router';
//以下是組件的導入
import { AppComponent } from './app.component';
import { HomeComponent } from  './home/home.component';
import { DetailComponent } from './detail/detail.component';
import { ContactComponent } from './contact/contact.component';
import { SidebarComponent } from './side-bar/sidebar.component';
import { ChildrenComponent } from './home/children/children.component';
import { PageNotComponent } from  './pagenot';

//定義路由規則,把這塊獨立出來
const appRoutes: Routes = [
  { path: 'home',component: HomeComponent, //首頁組件
    children:[{path: 'child',component: ChildrenComponent}]},  //首頁子路由組件
  { path: 'detail',component: DetailComponent}, //詳情頁組件
  { path: 'contact',component: ContactComponent},  //聯繫方式組件
  { path: '',redirectTo: '/home',pathMatch: 'full'},  //重定向組件
  { path: '**',component: PageNotComponent} //通配符路由組件
];


@NgModule({
  imports: [ RouterModule.forRoot(appRoutes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule {}
View Code 現在看起來舒服多了,每個版塊各司其職。但是大家有沒有想過,如果每個主要的組件比如首頁組件,詳情頁組件,聯繫方式組件裡面還有很多的子組件的話,那麼module.ts文件就會像懶婆娘的裹腳布一樣,又長又臭。

三、Angular路由的成熟期(惰性載入)

1.demo目錄

----------app.comonent.ts ----------app.component.html ----------pagenot.ts ----------pagenot.html(地址錯誤顯示界面) ----------app.module.ts ----------app-routing.module.ts ----------home(文件夾) ------------home.module.ts ------------home-routing.module.ts ------------home.component.ts ------------home.component.html ------------children(子路由文件夾) --------------children.component.ts --------------children.component.html ----------detail(文件夾) ------------detail.module.ts ------------detail-routing.module.ts ------------detail.component.ts ------------detail.component.html ----------contact(文件夾) ------------contact.module.ts ------------contact-routing.module.ts ------------contact.component.ts ------------contact.component.html ----------side-bar(文件夾) ------------sidebar.component.ts ------------sidebar.component.html 下麵代碼解析只解析有更改的部分

2.代碼講解

app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
//導入路由定義文件AppRoutingModule
import { AppRoutingModule } from './app-routing.module';
//以下是組件的導入
import { AppComponent } from './app.component';
import { PageNotComponent } from './pagenot';
import { SidebarComponent } from './side-bar/sidebar.component';

@NgModule({
  declarations: [
    AppComponent,
    PageNotComponent,
    SidebarComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
View Code 我們可以發現,不用導入首頁組件等組件了,而且這些父組件的子組件也不用導入了,當我們的項目很龐大的時候,一個父組件可能連一個表格都能分成一個子組件,用這種惰性載入的方式,極大地把項目模塊化管理。在這個demo中,比如首頁組件,首頁組件裡面假如有很多子組件,那麼我們要使用這些子組件的時候,肯定要在module.ts文件裡面導入並且註冊,有了惰性載入,我們就不用每個組件都在app.module.ts文件裡面註冊,而是在各自對應的父組件的module.ts文件比如home.module.ts裡面註冊。 app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { PageNotComponent } from './pagenot';
import { AppComponent } from './app.component';

@NgModule({
    imports: [
        RouterModule.forRoot([
            {   path: '', redirectTo: '/home', pathMatch: 'full'},
            {
                path: 'home',
                loadChildren: 'app/home/home.module#HomeModule' //Lazy load home module
            },
            {
                path: 'detail',
                loadChildren: 'app/detail/detail.module#DetailModule' //Lazy load detail module
            },
            {
                path: 'contact',
                loadChildren: 'app/contact/contact.module#ContactModule' //Lazy load contact module
            },
            { path: '**', component: PageNotComponent }
        ])
    ],
    exports: [RouterModule]
})
export class AppRoutingModule { }
View Code 當我們把RouterModule.forRoot改成RouterModule.forChild的時候,會出現這個錯誤 該錯誤是由於RouterModule.forChild()生成一個包含必要指令和路由但不包含路由服務的模塊而引起的。而RouterModule.forRoot(),它生成一個包含必要指令,路由和路由服務的模塊。 home.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HomeRoutingModule } from './home-routing.module';
//以下是組件的導入
import { HomeComponent } from './home.component';
import { ChildrenComponent } from './children/children.component';

@NgModule({
  declarations: [
    HomeComponent,
    ChildrenComponent
  ],
  imports: [
    BrowserModule,
    HomeRoutingModule
  ]
})
export class HomeModule { }
View Code home-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { HomeComponent } from  './home.component';
import { ChildrenComponent } from './children/children.component';

@NgModule({
    imports: [
        RouterModule.forChild([
            { 
              path: '', component: HomeComponent,
              children:[{ path: 'child', component:ChildrenComponent}]
            }
        ])
    ],
    exports: [
        RouterModule
    ]
})
export class HomeRoutingModule { }
View Code detail.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { DetailRoutingModule } from './detail-routing.module';
//以下是組件的導入
import { DetailComponent } from './detail.component';

@NgModule({
  declarations: [
    DetailComponent
  ],
  imports: [
    BrowserModule,
    DetailRoutingModule
  ]
})
export class DetailModule { }
View Code detail-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { DetailComponent } from  './detail.component';

@NgModule({
    imports: [
        RouterModule.forChild([
            {
                path: '',
                component: DetailComponent
            }
        ])
    ],
    exports: [
        RouterModule
    ]
})
export class DetailRoutingModule { }
View Code contact.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ContactRoutingModule } from './contact-routing.module';
//以下是組件的導入
import { ContactComponent } from './contact.component';

@NgModule({
  declarations: [
    ContactComponent
  ],
  imports: [
    BrowserModule,
    ContactRoutingModule
  ]
})
export class ContactModule { }
View Code contact-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { ContactComponent } from  './contact.component';

@NgModule({
    imports: [
        RouterModule.forChild([
            { path: '', component: ContactComponent }
        ])
    ],
    exports: [
        RouterModule
    ]
})
export class ContactRoutingModule { }
View Code

四、結語

在做大型項目的時候,惰性載入無疑是比較好的選擇,各個模塊的路由各自對自己負責,有什麼子組件就在自己的module.ts文件註冊,有什麼路由規則就在各自的routing.module.ts文件裡面定義,最後在整合代碼的時候,直接拷貝整個文件夾就可以了,非常方便。







您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 介紹 釘釘,阿裡巴巴出品,專為中國企業打造的免費智能移動辦公平臺,含PC版,Web版和手機版。智能辦公電話,消息已讀未讀,DING消息任務管理,讓溝通更高效;移動辦公考勤,簽到,審批,企業郵箱,企業網盤,企業通訊錄,讓工作更簡單;酷公司,用釘釘,隨時隨地移動辦公。 由於目前的版本郵件警報暫時走不通, ...
  • 負載均衡集群企業級應用實戰-LVS 實現基於LVS負載均衡集群的電商網站架構 隨著業務的發展,網站的訪問量越來越大,網站訪問量已經從原來的1000QPS,變為3000QPS,網站已經不堪重負,響應緩慢,面對此場景,單純靠單台LNMP的架構已經無法承載更多的用戶訪問,此時需要用負載均衡技術,對網站容量 ...
  • 恢復內容開始 設計模式(design patterns)是一套被反覆使用,多數人知曉的,經過分類編目的,使用設計模式是 為了可重用代碼,讓代碼更容易更容易被他人理解,保證代碼可靠性。 設計模式一共有23種: 1. 設計者模式分類 (三大類) 創建者模式: 一共分5種 工廠方法模式 , 抽象工廠模式, ...
  • CDN的全稱是Content Delivery Network,即內容分髮網絡。 其基本思路是儘可能避開互聯網上有可能影響數據傳輸速度和穩定性的瓶頸和環節,使內容傳輸的更快、更穩定。通過在網路各處放置節點伺服器所構成的在現有的互聯網基礎之上的一層智能虛擬網路,CDN系統能夠實時地根據網路流量和... ...
  • 題目1:通過代碼描述每一天的不同時間段的工作效率 分析: 首先確定,工作狀態指正在工作,或者以及下班這些情況,而這些情況所受影響的因素包括:當前時間以及任務是否已經完成。所以在Work中需要兩個屬性:hour和finish。然後根據這兩個屬性直接判斷當前的工作狀態即可。 實現: 1 class Pr ...
  • 1. 什麼是領域(Domain) 我們所做的軟體系統的目的都是來解決一系列問題,例如做一個電商系統來線上銷售自己企業的產品;做一個灰度發佈平臺來提升服務的質量和穩定性。任何一個系統都會屬於某個特定的領域,例如: 論壇是一個領域:要做一個論壇,那這個論壇的核心業務是確定的:比如用戶發帖、回帖等核心基本 ...
  • 複習一下: | 基礎模塊 | 作用 | | | | | fs | fs模塊用於對系統文件及目錄進行讀寫操作 | | http | 創建伺服器。e.g.http.createServer(); | | queryString | 把url帶的參數串轉化為數組對象 | | url | 直接解析URL中字 ...
  • 這篇文章主要對vue的理解進行總結: 參考來源:http://blog.csdn.net/generon/article/details/72482844 vue.js是一套構建用戶界面的漸進式框架,它的核心庫只關註視圖層。它相比之其它的框架來說要更加的輕便,易於上手,相對與大部分的框架在性能方面要 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...