都9102年了,筆者所在的公司的主要項目仍是用AngularJS 1.6這種史詩的框架進行開發的。另外因爲歷史的緣由,代碼的凌亂程度早已超越想象。爲此,筆者決定痛下決心把整個項目重構了一遍...今後踏上了Angular升(跳)級(坑)之路。html
AngularJS的例子項目angular-phonecathtml5
在上篇文章中,項目已經基本能正常運行了。但其實在項目裏還有許多未解決的問題,其中包括:git
在項目中使用的是雙路由的策略。即ng1(AngularJS)、ngx(Angular)各自的頁面其實仍是用相應的路由進行管理的。所以,兩個路由間須要一個「橋樑」進行通訊,讓他們彼此間的數據進行同步,而這個「橋樑」官方早已爲咱們提供好了,那就是setUpLocationSync
。
在使用「橋樑」進行通訊前,還需對路由進行改造,讓它們更符合咱們項目的需求。github
在ngx的路由器中,默認使用的是history模式的路由形式。但ng1路由器中默認使用的則是hash模式的路由形式。所以,咱們首先要作的,就是要讓它們的模式設置爲一致。
hash和history模式各有利弊,它們之間的區別能夠參考附錄:LocationStrategy 以及瀏覽器 URL 樣式。筆者更推薦使用history模式,由於他更符合瀏覽器的URL風格。
下面介紹一下它們各自的設置方法:gulp
若是使用history模式,那麼你主要修改ng1的路由器配置。bootstrap
angular. module('phonecatApp'). config(['$routeProvider','$locationProvider', function config($routeProvider,$locationProvider) { $locationProvider.html5Mode(true) // 設置爲html5 mode } ]); 複製代碼
若是使用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('') } ]); 複製代碼
在實際的項目中,有些頁面是基於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...
如今,就讓它們的狀態同步吧。
在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…]
本做品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。