和(hé)尤雨溪一(yī)起進階vue
1 初級版
借助vue的(de)動态組件,可(kě)以實現一(yī)個簡單的(de)路由功能,如(rú)下
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<div id="app">
<a href="#foo">foo</a>
<a href="#bar">bar</a>
<component :is="url"></component>
</div>
<script>
// 這是一(yī)個比較簡單的(de)解決方案,但是有一(yī)個問題,初始化的(de)時候無法匹配
window.addEventListener('hashchange', () => {
app.url = window.location.hash.slice(1)
});
let app = new Vue({
el: '#app',
data() {
return {
url: null
}
},
components: {
foo: {template: `<div>foo-component</div>`},
bar: {template: `<div>bar-component</div>`}
} })
</script>2 改進版
解耦微改進一(yī)下,将路由提取到一(yī)個路由表中,
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<div id="app"> </div>
<script>
const Foo = {template: '<div>foo</div>'}
const Bar = {template: '<div>bar</div>'}
const NotFound = {template: '<div>not found</div>'}
// 在對象裏面統一(yī)配置路由
const routeTable = { 'foo': Foo, 'bar': Bar }
window.addEventListener('hashchange', () => { app.url = window.location.hash.slice(1) })
let app = new Vue({
el:'#app',
data() {
return {
url: window.location.hash.slice(1)
} },
render(h) {
return h('div', [
h('a', {attrs: {href: '#foo'}}, 'foo'),
'|',
h('a', {attrs: {href: '#bar'}}, 'bar'),
h(routeTable[this.url] || NotFound),
])
} })
</script>3 最終版
上面都是處理(lǐ)簡單的(de)url, 實際開發的(de)時候,配置的(de)路由都是多頁面,多組件,路由的(de)path也會比較長(cháng),如(rú)/a/b, /a/b/c, 還有動态路由,比如(rú)/a/:id,這個時候上面的(de)方法就不能準确匹配了, 如(rú)果你是正則達人,你可(kě)以自(zì)己試試解析這些複雜的(de)path,不是的(de)話就使用别人封裝好的(de)第三方庫吧(ba),這裏推薦path-to-regexp, 這個庫的(de)作用作者一(yī)句話就概述完了:
Turn a path string such as/user/:nameinto a regular expression
大家可(kě)以點進去(qù)鏈接了解一(yī)下用法,這裏我們介紹接下來要用的(de)部分
const keys = [] const regexp = pathToRegexp('/foo/:id', keys) // regexp = /^\/foo\/((?:[^\/]+?))(?:\/(?=$))?$/i // keys = [{ delimiter: "/", name: "id", optional: false, partial: false, pattern: "[^\/]+?", prefix: "/", repeat: false}] // 得到了正則表達式regexp, 傳入實際的(de)url執行正則的(de)exec方法 // 不匹配 const match1 = regexp.exec('/test/route'); // null const match3 = regexp.exec('/foo'); // null // 匹配 const match2 = regexp.exec('/foo/fooId'); // ["/foo/fooId", "fooId", index: 0, input: "/foo/fooId", groups: undefined] 複制代碼ok, 我們可(kě)以解析path了,來看看接下來如(rú)何實現
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
// 這裏是下載到本地(dì)同目錄引入的(de)
<script src='./path-to-regexp.js'></script>
<div id="app"></div>
<script>
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, }
// 處理(lǐ)路由
const compiledRoutes = [];
Object.keys(routeTable).forEach(path => {
const dynamicSegments = []
const regex = pathToRegexp(path, dynamicSegments)
const component = routeTable[path]
compiledRoutes.push({
component,
regex,
dynamicSegments
}) })
window.addEventListener('hashchange', () => {
app.url = window.location.hash.slice(1);
})
const app = new Vue({
el: '#app',
data() {
return {
url: window.location.hash.slice(1)
}
},
// 渲染那個路由,路由屬性
render(h) {
const url = '/' + this.url
let componentToRender
let props = {}
compiledRoutes.some(route => {
const match = route.regex.exec(url)
if (match) {
componentToRender = route.component
// 上一(yī)步已經可(kě)以匹配到url對應的(de)組件了
// 這裏多做(zuò)一(yī)步,獲取動态id作為(wèi)props的(de)屬性傳入組件
route.dynamicSegments.forEach((segment,index) => {
props[segment.name] = match[index+1]
})
}
})
return h('div', [
h('a', { attrs: { href: '#foo/123' } }, 'foo123'),
'|',
h('a', { attrs: { href: '#foo/234' } }, 'foo234'),
'|',
h('a', { attrs: { href: '#bar' } }, 'bar'),
h(componentToRender || NotFound, { props })
])
}
})
</script>編輯:--史志成
南順網絡








