[使用 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,须要结合应用自身的特性和需求具体分析。

相关文章
相关标签/搜索