使用Angular cli升級AngularJS項目——(二)同步混合應用路由的狀態

前言

都9102年了,筆者所在的公司的主要項目仍是用AngularJS 1.6這種史詩的框架進行開發的。另外因爲歷史的緣由,代碼的凌亂程度早已超越想象。爲此,筆者決定痛下決心把整個項目重構了一遍...今後踏上了Angular升(跳)級(坑)之路。html

系列文章

  1. (一)引導運行混合應用
  2. (二)同步混合應用路由的狀態

在這個系列文章中涉及到

  1. Angular與AngularJS如何共存開發
  2. 使用Angular Cli編譯及開發Angular、AngularJS混合應用
  3. 如何在Hash模式中同步AngularJS、Angular的路由
    ---下面是坑,待填
  4. 在gulp或其餘自動化構建工具中使用Angular CLI
  5. 在Angular中使用AngularJS的組件
  6. 在AngularJS中使用Angular的組件

本文使用的例子項目

AngularJS的例子項目angular-phonecathtml5

1、路由的管理

在上篇文章中,項目已經基本能正常運行了。但其實在項目裏還有許多未解決的問題,其中包括:git

  1. 兩個框架中的路由狀態不一樣步。
  2. 在切換路由後,刷新頁面,路由消失。

在項目中使用的是雙路由的策略。即ng1(AngularJS)、ngx(Angular)各自的頁面其實仍是用相應的路由進行管理的。所以,兩個路由間須要一個「橋樑」進行通訊,讓他們彼此間的數據進行同步,而這個「橋樑」官方早已爲咱們提供好了,那就是setUpLocationSync
在使用「橋樑」進行通訊前,還需對路由進行改造,讓它們更符合咱們項目的需求。github

2、hash模式仍是history模式

在ngx的路由器中,默認使用的是history模式的路由形式。但ng1路由器中默認使用的則是hash模式的路由形式。所以,咱們首先要作的,就是要讓它們的模式設置爲一致。
hash和history模式各有利弊,它們之間的區別能夠參考附錄:LocationStrategy 以及瀏覽器 URL 樣式。筆者更推薦使用history模式,由於他更符合瀏覽器的URL風格。
下面介紹一下它們各自的設置方法:gulp

history模式:

若是使用history模式,那麼你主要修改ng1的路由器配置。bootstrap

angular.
  module('phonecatApp').
  config(['$routeProvider','$locationProvider',
    function config($routeProvider,$locationProvider) {
      $locationProvider.html5Mode(true)  // 設置爲html5 mode
    }
  ]);
複製代碼

hash模式:

若是使用hash模式,那麼你主要修改的就是Angular的路由配置。瀏覽器

@NgModule({
  imports: [RouterModule.forRoot(routes,{
    useHash: true
  })]
})
export class AppRoutingModule {
}
複製代碼

在ng1.6你可能使用的是hash-bang模式,或者在ng1中設置了任何的前綴,你須要將其前綴去掉。bash

angular.
  module('phonecatApp').
  config(['$locationProvider',
    function config($locationProvider) {
      $locationProvider.hashPrefix('') 
    }
  ]);
複製代碼

3、凹槽路由

在實際的項目中,有些頁面是基於ng1寫的,有些頁面是基於ngx寫的。在多數狀況下,咱們天然是但願能各自顯示頁面相互不被打擾。所以,咱們須要作一個「凹槽路由」讓它們能自由切換。(文段參考 2)
那麼。凹槽路由到底是什麼?簡單而言就是「空頁面」。在顯示ng1的頁面時,ngx部分顯示一個空白的頁面不就能夠了?同理的,在顯示ngx的頁面,咱們進行相應的操做。
在ng1中實現比較簡單:markdown

angular.
  module('phonecatApp').
 config(['$routeProvider',
    function config($routeProvider) {
      $routeProvider.
        ..., // 此處省略其餘路由
        otherwise({
          template: ''
        });
    }
  ]);
複製代碼

在ngx中,你須要添加一個"空"的Componentapp

ng g component empty
複製代碼

而後,在路由中添加

const routes: Routes = [
  ...,
  {
    path: '**',
    component: EmptyComponent
  }
]
複製代碼

ALL DONE...

4、同步你的路由狀態

如今,就讓它們的狀態同步吧。
在history mode下很是簡單。只需用到官方提供的setUpLocationSync便可。

export class AppModule implements DoBootstrap {

    ngDoBootstrap(appRef: ApplicationRef) {
    this.upgrade.bootstrap(document.documentElement, ['phonecatApp']);
    // setUpLocationSync 需在UpgradeModule.bootstrap後引用
     setUpLocationSync(upgrade);
  }
 }
複製代碼

那在hash mode下呢?那就沒這麼簡單了。
筆者曾經直接使用setUpLocationSync這個方法致使筆者直接懷疑人生——每次跳轉路由都會出現死循環。 爲何會出現這種狀況呢?setUpLocationSync這個方法是@angular/router提供的函數,通常不會出現問題。但此次致使循環的問題,就是出如今這個函數身上。在upgrage.ts中,能夠看到

ngUpgrade.$injector.get('$rootScope')
      .$on('$locationChangeStart', (_: any, next: string, __: string) => {
        const url = resolveUrl(next);
        const path = location.normalize(url.pathname);
        router.navigateByUrl(path + url.search + url.hash);
      });
複製代碼

在ng1觸發locationChangeStart這個事件後,這個函數直接將URL中的path + url.search + url.hash傳遞給ngx的Router,然而hash mode中應該須要將hash做爲路徑傳遞。所以,要在hash mode中同步狀態,須要將router.navigateByUrl(path + url.search + url.hash);改成this.router.navigateByUrl(url.hash + url.search)
在本文的例子中在原有的setUpLocationSync的基礎上實現了路由器的同步: location-sync.service.ts

附:相鄰路由出口?

在參考文章中升級 AngularJS 至 Angular提到了「相鄰路由出口」。
在實際運用中,經過它能夠作一些如懶加載的ng1的模塊等實現。須要注意的是,若是在組件(Component)中放入ng1的入口,那麼調用UpgradeModule.bootstrap須要在該組件視圖加載完畢後,如ngAfterViewInit鉤子等等。

源碼

在此,你能夠獲取到本文修改後的angular-phonecat項目。 [github.com/yskun/angul…]

參考

  1. 從 AngularJS 升級到 Angular
  2. 升級 AngularJS 至 Angular

License

本做品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。

相關文章
相關標籤/搜索