使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。
Hash URL,当 # 后面的哈希值发生变化时,不会向服务器请求数据,可以通过 hashchange 事件来监听到 URL 的变化,从而进行跳转页面。
依赖 HTML5 History API 和服务器配置
支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home.vue'
import Demo from '@/views/Demo.vue'
import InstantMessager from '@/views/InstantMessager'
import Seller from '@/views/Seller'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/demo',
name: 'Demo',
component: Demo,
meta: {
isFullPage: true
}
},
{
path: '/instantMessager',
name: 'InstantMessager',
component: InstantMessager,
},
{
path: '/seller',
name: 'Seller',
component: Seller,
meta: {
isFullPage: true
}
},
]
const router = new VueRouter({
mode: '',
base: process.env.BASE_URL,
routes
})
export default router
Vue.use(VueRouter)会执行install方法
1、在beforeCreated中初始化vue-router,并将_route响应式
2、在 Vue 原型上添加 r o u t e r 属 性 ( V u e R o u t e r ) 并 代 理 到 t h i s . router 属性( VueRouter )并代理到 this.router属性(VueRouter)并代理到this.root._router
3、Vue上注册router-link和router-view两个组件
export function install (Vue) {
if (install.installed && _Vue === Vue) return
install.installed = true
_Vue = Vue
const isDef = v => v !== undefined
const registerInstance = (vm, callVal) => {
let i = vm.$options._parentVnode
if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
i(vm, callVal)
}
}
Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) {
this._routerRoot = this
this._router = this.$options.router
this._router.init(this)
Vue.util.defineReactive(this, '_route', this._router.history.current)
} else {
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})
Object.defineProperty(Vue.prototype, '$router', {
get () { return this._routerRoot._router }
})
Object.defineProperty(Vue.prototype, '$route', {
get () { return this._routerRoot._route }
})
Vue.component('RouterView', View)
Vue.component('RouterLink', Link)
const strats = Vue.config.optionMergeStrategies
// use the same hook merging strategy for route hooks
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}
生成实例过程中,主要做了以下两件事
1、根据配置数组(传入的routes)生成路由配置记录表。
2、根据不同模式生成监控路由变化的History对象
首先我们看到在new VueRouter()的时候传入的参数,比如mode,base,routes等。mode是导航模式,有hash(默认),history,abstract。
hash 是默认值,如果不传入或者浏览器不支持history时,就用hash。
class VueRouter {
constructor (options: RouterOptions = {}) {
this.app = null
this.apps = []
this.options = options
this.beforeHooks = []
this.resolveHooks = []
this.afterHooks = []
this.matcher = createMatcher(options.routes || [], this)
let mode = options.mode || 'hash'
this.fallback =
mode === 'history' && !supportsPushState && options.fallback !== false
if (this.fallback) {
mode = 'hash'
}
if (!inBrowser) {
mode = 'abstract'
}
this.mode = mode
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if (process.env.NODE_ENV !== 'production') {
assert(false, `invalid mode: ${mode}`)
}
}
}
1). createMatcher
根据routes数组,做一个映射,返回match、addRoutes 、addRoute、getRoutes 方法。
this.matcher = createMatcher(options.routes || [], this)
// 方法createMatcher:
export function createMatcher (
routes: Array,
router: VueRouter
): Matcher {
const { pathList, pathMap, nameMap } = createRouteMap(routes)
function addRoutes (routes) { }
function addRoute (parentOrRoute, route) {}
function getRoutes () { }
function match { }
return {
match,
addRoute,
getRoutes,
addRoutes
}
}
2)createRouteMap, 创建路由映射表, 路径/名称的映射表,生成路由记录(route records);
const { pathList, pathMap, nameMap } = createRouteMap(routes)
路由记录属性如下:
const record: RouteRecord = {
path: normalizedPath,
regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
components: route.components || { default: route.component },
alias: route.alias
? typeof route.alias === 'string'
? [route.alias]
: route.alias
: [],
instances: {},
enteredCbs: {},
name,
parent,
matchAs,
redirect: route.redirect,
beforeEnter: route.beforeEnter,
meta: route.meta || {},
props:
route.props == null
? {}
: route.components
? route.props
: { default: route.props }
}
如某一条路由记录
createRouteMap为每条路由生成路由记录,结果如下:
2)判断mode的值,根据不同的mode走不同的方法,
若浏览器不支持HTML5History方式(通过supportsPushState变量判断),则mode强制设为’hash’;若不是在浏览器环境下运行,则mode强制设为’abstract’
点击跳转主线:
this.$router.push(’/demo’) ->History.push -> transitionTo -> match -> createRoute -> confirmTransition -> updateRoute-> render