vue-router
vue-router是Vue框架的另一个强大工具。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。
哈希路由
单页应用路由,我们有一些url,想把他们映射到组件。即使组件和这些url有一一对应的关系,并能够实现跳转。
<div id="app">
<component :is="url"></component>
<a @click="routeTo('#foo')" href="#foo">foo</a>
<a @click="routeTo('#bar')" href="#bar">bar</a>
</div>
<script>
//一个基于哈希的路由解决方案
/*
浏览器有两种方式进行路由,可以使用哈希,也可以使用HTML5 History API。
从某种意义上说,Html5 History APi更好,它支持弹出状态,你的URL看起来会更好,但是他需要某种服务器配置
为了更方便的展示,这里使用哈希方式访问。
*/
window.addEventListener('hashchange', () => {
app.url = window.location.hash.slice(1)
})
const app = new Vue({
el: '#app',
data: {
url: 'foo'
},
components: {
foo: { template: `<div>foo</div>`},
bar: { template: `<div>bar</div>`},
},
methods: {
routeTo (route) {
window.location.hash = route
}
}
})
</script>
路由表
完成了基础路由跳转的实现,那么我们能不能把基础路由和组件的对应关系维护起来,形成一张表,这样当我们需要跳转的时候查询路由表再跳转对应组件就好了。
<div id="app">
<component :is="matchedComponent"></component>
<a href="#foo">foo</a>
<a href="#bar">bar</a>
</div>
<script>
// '#/foo' -> Foo
// '#/bar' -> Bar
// '#/404' -> NotFound
const Foo = { template: `<div>foo</div>` }
const Bar = { template: `<div>bar</div>` }
const NotFound = { template: `<div>not found!</div>` }
//路由表,维护组件和路径的对应关系
const routeTable = {
foo: Foo,
bar: Bar
}
window.addEventListener('hashchange', () => {
app.url = window.location.hash.slice(1)
})
const app = new Vue({
el: '#app',
data: {
url: 'foo'
},
//两种视图实现方式,render渲染函数和html模板
render (h) {
return h('div', [
h(routeTable[this.url] || NotFound),
h('a',{ attrs:{ href:'#foo'}}, 'foo'),
' | ',
h('a',{ attrs:{ href:'#bar'}}, 'bar')
])
}
// computed: {
// matchedComponent () {
// return routeTable[this.url] || NotFound
// }
// }
})
</script>
正则匹配动态路由
正则匹配
使用path-to-regexp工具库中的pathToRegexp函数处理url中的地址和参数
动态路由的匹配
<div id="app"></div>
<script>
// '#/foo/123' -> foo with id: 123
// '#/bar' -> Bar
// '#/404' -> NotFound
// path-to-regexp usage:
// const regex = pathToRegexp(pattern)
// const match = regex.exec(path)
//根据路由展现的组件
const Foo = {
props: ['id'],
template: `<div>foo with id: {{ id }}</div>`
}
const Bar = { template: `<div>bar</div>` }
const NotFound = { template: `<div>not found!</div>` }
//正则捕获的路由表
const routeTable = {
'/foo/:id': Foo,
'/bar': Bar
}
//编译完成后的数组,就是经过正则匹配后的数组
const compiledRoutes = []
//取出路由表中的所有匹配规则
Object.keys(routeTable).forEach(key => {
const dynamicSegments = []
//工具库函数pathToRegexp,用于处理url中的地址和参数
const regex = pathToRegexp(key, dynamicSegments)
const component = routeTable[key]
compiledRoutes.push({
//对应规则映射组件
component,
//匹配规则
regex,
//解析动态匹配部分
dynamicSegments
})
})
window.addEventListener('hashchange', () => {
app.url = window.location.hash.slice(1)
})
const app = new Vue({
el: '#app',
data: {
url: window.location.hash.slice(1)
},
render (h) {
const path = '/' + this.url
let componentToRender
let props = {}
//检查是否有匹配上的路由
compiledRoutes.some(route => {
const match = route.regex.exec(path)
componentToRender = NotFound
//判断匹配是否成功
if (match) {
componentToRender = route.component
route.dynamicSegments.forEach((segment, index) => {
props[segment.name] = match[index + 1]
})
return true
}
})
return h('div', [
h(componentToRender, { props }),
h('a', { attrs: { href: '#foo/123' }}, 'foo 123'),
' | ',
h('a', { attrs: { href: '#foo/234' }}, 'foo 234'),
' | ',
h('a', { attrs: { href: '#bar' }}, 'bar'),
' | ',
h('a', { attrs: { href: '#garbage' }}, 'garbage')
])
}
})
</script>