[使用 Weex 和 Vue 開發原生應用] 6 使用 vue-router

系列文章的目錄在 ? 這裏javascript

(因爲 我比較懶 最近一段時間在忙其餘事,系列文章拖了很久終於又更新了。。。)html

什麼是 vue-router ?

vue-router 官方文檔前端

vue-router 是針對 Vue.js 開發的前端路由工具,能夠很方便的開發單頁應用。vue

單頁應用

單頁應用的概念其實很早就出現了,它是指在同一個頁面內包含了應用的全部功能,一個頁面就是一個應用,整個應用只有一個頁面,是在 Web 場景下提出的一種開發方式。單頁應用的特性在文末討論,這裏先說用法。java

怎麼在 Weex 裏引入 vue-router

vue-router 是以 Vue.js 插件的形式存在的,使用前必需要引入 Vue.js。由於 WeexSDK (>= 0.9.5)中已經包含了 Vue.js Runtime,因此不須要再引入一遍 Vue.js ,只需引入 vue-router 並註冊便可:git

// import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

使用 vue-router 的例子

定義根視圖

經過在模板中添加 <router-view> 的方式定義路由出口,路由匹配到的組件將會替換這個標籤。github

<!-- App.vue -->

<template>
  <router-view></router-view>
</template>

在模板中也能夠包含其餘標籤, <router-view> 也能夠是其餘標籤的子標籤,和其餘標籤的用法是同樣的;在 vue-router 的內部實現中,router-view 的實現就是一個普通的函數式組件。web

配置路由規則

在嚮應用中註冊 router 以前,須要先建立路由實例,而且配置路由規則。vue-router

// router.js

import VueRouter from 'vue-router'
import HomeView from 'path/to/HomeView.vue'
import AboutView from 'path/to/AboutView.vue'

Vue.use(VueRouter)

export default new VueRouter({
  routes: [
    { path: '/home',  component: HomeView  },
    { path: '/about', component: AboutView }
  ]
})

上述代碼中建立了 VueRouter 的實例,而且傳入了 routes 配置,當路徑是 home 時,頁面就會跳轉到 HomeView 組件,HomeView.vue 就會渲染到 App.vue 中 <router-view> 標籤的位置。同理,當路徑是 about 時,頁面就會跳轉到 AboutView 組件。vuex

給應用注入路由功能

想要在應用中注入路由功能,還有給入口組件添加 router 屬性,使應用和路由創建聯繫。

import App from 'path/to/App.vue'
import router from 'path/to/router.js'

App.el = '#root'
App.router = router

new Vue(App)

注意事項

前邊提到過,單頁應用是在 Web 場景下提出的一種開發方式,它的具體實現依賴了 Web 平臺的功能,如 Histroy API 和 URL Hash 等特性。然而 Weex 的運行環境不僅是瀏覽器,一般是以移動端原生環境爲主,這些特性在 Weex 中並不徹底適用,參考《Weex 和 Web 平臺的差別》

針對這些平臺差別,有如下兩點須要注意:

路由模式

在 vue-router 的配置項中,有一個 mode 參數能夠用來指定 vue-router 的運行模式。

  • hash: 使用 URL hash 值來做路由。默認模式。

  • history: 依賴 HTML5 History API 和服務器配置。查看 HTML5 History 模式

  • abstract: 支持全部 JavaScript 運行環境,如 Node.js 服務器端。

根據平臺差別能夠看出,在 Weex 環境中只支持使用 abstract 模式。 不過,vue-router 自身會對環境作校驗,若是發現沒有瀏覽器的 API,vue-router 會自動強制進入 abstract 模式,因此 在使用 vue-router 時只要不寫 mode 配置便可,默認會在瀏覽器環境中使用 hash 模式,在移動端原生環境中使用 abstract 模式。 (固然,你也能夠明確指定在全部狀況下都使用 abstract 模式)

編程式導航

vue-router 支持使用 <router-link> 建立導航連接,不過在其中使用了基於 DOM 事件的一些特性,這些特性在 Weex 原生環境中並不能很好的工做。因此 在 Weex 中,你必須使用編程式導航來編寫頁面跳轉邏輯。 用法參考 Weex 官方文檔

更多功能

除了上述最基本的特性之外,vue-router 還有不少很強大的功能,具體使用方法建議參考其官方文檔,這裏再也不贅述。

實際項目中的 vue-router

weex-hackernews 項目中使用了 vue-router 作路由管理。

圖片描述

路由配置

其中表頭的五個一級菜單(Top 、New 、Show 、Ask 、Job),就對應了五個不一樣的路由路徑,也對應了五個列表組件。除此以外,還有列表頁、評論頁、用戶信息頁也都對應了單獨的路由路徑。具體配置在 src/router.js 中,以下所示:

export default new Router({
  routes: [
    { path: '/top', component: createStoriesView('top') },
    { path: '/new', component: createStoriesView('new') },
    { path: '/show', component: createStoriesView('show') },
    { path: '/ask', component: createStoriesView('ask') },
    { path: '/job', component: createStoriesView('job') },
    { path: '/article/:url(.*)?', component: ArticleView },
    { path: '/item/:id(\\d+)', component: CommentView },
    { path: '/user/:id', component: UserView },
    { path: '/', redirect: '/top' }
  ]
})

其中 article 、item 和 user 三個配置項中用到了動態路由匹配,把全部同類路由都映射到了同一個組件上,組件結構相同,可是參數是不一樣的(url 不一樣或者 id 不一樣)。

在最後還配置了路由重定向,將默認根路由 / 重定向到了 /top,默認加載「最熱」文章列表。

在應用中註冊路由

若要應用組件和路由之間創建聯繫,須要給入口組件注入 router 屬性。代碼在 src/entry.js 中。

new Vue(Vue.util.extend({ router }, App))

router.push('/')

代碼在建立 Vue 實例前在 App 上添加了 router 屬性,使得應用組件中都能經過 this.$router 獲取到路由數據。在建立實例後,手動調用 router.push('/') 跳轉到根視圖。

同步 Vuex 和 vue-router 的狀態

使用 vuex-router-sync 能夠很方便地同步 Vuex 和 vue-router 的狀態,這個步驟並非必須的,可是能夠簡化代碼的使用。實際代碼在 src/entry.js 中,以下所示:

sync(store, router)

代碼的效果就是註冊了 store.state.route 這個變量,使得在 Vuex 的 Store 中能夠獲取到 route 對象,這在一些比較複雜的大型應用中可能會用到。

因爲在根組件中已經注入了 router 屬性,在全部組件中也均可以經過 this.$router 獲取到當前的路由狀態。

Weex 適合寫單頁應用嗎 ?

如下是我我的的觀點,不表明任何人,也不表明 Weex。

不考慮技術細節,從實際應用的角度聊一下我對「單頁應用」的見解。

單頁應用也有很多的優點和缺陷:

  • 優點:頁面無需刷新;能夠實現更好的過渡效果;組件複用;狀態共享。

  • 缺陷:初次加載白屏時間長;不利於 SEO;有大量全局狀態;技術方法相對複雜,有學習成本。

大部分特性都已經有共識,我也再也不展開對比,這裏着重討論一下在 移動端Weex 平臺 中使用單頁應用的狀況。

頁面間狀態的共享與隔離

單頁應用運行在同一個 javascript runtime 裏,也就是說頁面的狀態都是共享的,環境變量也是相同的,這一點實際上是有不少隱患。在移動應用中,單頁應用不只耗費內存,也很容易發生內存泄露。

全部的 Weex 頁面,不管是基於 Vue 仍是 Rax,都共用一個 Weex Runtime,其中的 js 引擎也只初始化一次,除非從新初始化 Weex SDK(應用重啓),全部頁面對環境的操做痕跡都將保留。在這種情景下,頁面間狀態的隔離就尤其重要,共享的全局狀態極可能會成爲內存泄露的元兇。

換句話說,若是某個頁面建立了一個臨時的全局變量,可是在頁面退出後沒有清除,這個變量將一直保留在內存中;若是某個頁面在全局狀態上掛載了某個屬性,可是頁面退出後沒有斷開鏈接,這個屬性也會一直保留在全局狀態中。

原生應用自己就是多頁的場景,頁面間狀態的隔離比共享更重要一些。

資源加載和緩存

單頁應用要把全部頁面用到資源(至少是腳本)提早打包在一塊兒,一次性所有發到客戶端,首次打開的網絡耗時會比較久,容易致使長時間白屏,很難遞進的加載資源,沒法作到「先加載有用的」。若是有多個單頁應用都須要用到某些頁面或者某個組件,是很難複用的,也很難加緩存,難不成整個移動應用都寫成一個大「單頁」的嗎? Web 上或許能夠考慮,可是原生應用裏十分不建議這樣作。應用都規模越大,這些缺陷就越明顯。

更況且如今 HTTP/2 逐漸普及,有了多路複用,把資源粒度劃分的細一些更有利於瀏覽器的加載。還有 prefetch 和 preload 這種特性能夠提高資源加載的效率,Weex 也在考慮支持。瀏覽器也逐漸開始支持 ES6 module,能夠直接經過 <script type="module"> 的方式引入 ES6 模塊,代碼的管理和加載可能會以 模塊 爲單元,而不是頁面。

從一系列技術趨勢來看,如今有不少技術方案都講究將資源細分,巴不得使用 code split 把代碼細分到組件級別(「打包」是一個暫時性的讓人又愛又恨的工做)。

Histroy API 和 hash

單頁應用在技術上基本上都是基於 Histroy API 或 hash 連接實現,即便不直接依賴,也會模擬這方面的行爲(polyfill)。前邊也提到過 Weex 和 Web 平臺有差別, Histroy API 和 hash 這些都是瀏覽器中的概念,和 Weex 裏不徹底對應。

使用 Weex 開發的是原生應用,頁面棧的管理使用的也是原生的特性,沒有 Histroy API 可是有 navigator 模塊 能夠實現頁面的「前進」和「後退」等操做。其實我以爲原生開發中 Navigator 的概念比 web 上 History API 設計的更完善一些(因爲多端行爲有差別,Weex 只暴露了部分通用功能),可操做性也更強。至於 hash,移動端不會輕易暴露頁面 url,更不用說 hash 了。

一句話總結: Weex 是跨平臺的,Histroy API 是針對 Web 平臺設計的,未必適合原生開發。

小結

技術自己是客觀的,有各自的適用場景。weex-hackernews 項目自己的頁面也很少,多個頁面之間的確會共用一些數據;並且原本這就是一個範例項目,爲了展現能力和用法的,因此我用了 vue-router。在你的應用中是否應該引入 vue-router,須要結合應用自身的特性和需求具體分析。

相關文章
相關標籤/搜索