话不多说,用过 vue-router 就知道这篇在讲什么。
前端路由主要分为 hash 模式和 history 模式。
hash
hash 模式使用 onhashchange 事件监听 hash 值变化:
1 2 3 4
| window.onhashchange = function () { }
|
history
详情见(mdn)[https://developer.mozilla.org/zh-CN/docs/Web/API/History]
实践
首先定义 BaseRouter:
1 2 3 4 5 6 7 8 9 10 11 12
| class BaseRouter { constructor(list) { this.list = list } render(state) { let ele = this.list.find((ele) => ele.path === state) ele = ele ? ele : this.list.find((ele) => ele.path === '*') ELEMENT.innerText = ele.component } }
|
BaseRouter 接收路由数组,定义 render 函数用来渲染对应 html。
有了 base,我们就来挨个实现 hash 和 history。
不管是 hash 还是 history,我们都要实现同样的几个方法:hander、getState、getUrl、push、replace、go
接下来先实现 hash 模式的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import { BaseRouter } from './base.js'
class HashRouter extends BaseRouter { constructor(list) { super(list) this.handler() window.addEventListener('hashchange', (e) => { this.handler() }) } handler() { this.render(this.getState()) } getState() { const hash = window.location.hash return hash ? hash.slice(1) : '/' } getUrl(path) { const href = window.location.href const i = href.indexOf('#') const base = i >= 0 ? href.slice(0, i) : href return `${base}#${path}` } push(path) { window.location.hash = path } replace(path) { window.location.replace(this.getUrl(path)) } go(n) { window.history.go(n) } }
|
然后是 historyRender:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import { BaseRouter } from './base.js'
export class HistoryRouter extends BaseRouter { constructor(list) { super(list) this.handler() window.addEventListener('popstate', (e) => { this.handler() }) } handler() { this.render(this.getState()) } getState() { const path = window.location.pathname return path ? path : '/' } push(path) { history.pushState(null, null, path) this.handler() } replace(path) { history.replaceState(null, null, path) this.handler() } go(n) { window.history.go(n) } }
|
然后我们定义一个路由数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| export const ROUTELIST = [ { path: '/', name: 'index', component: 'This is index page', }, { path: '/hash', name: 'hash', component: 'This is hash page', }, { path: '/history', name: 'history', component: 'This is history page', }, { path: '*', name: 'notFound', component: '404 NOT FOUND', }, ]
|
然后在 index.js 中 init:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import { HashRouter } from './hash' import { HistoryRouter } from './history' import { ROUTELIST } from './routeList'
const MODE = 'history' class WebRouter { constructor({ mode, routeList }) { this.router = mode === 'hash' ? new HashRouter(routeList) : new HistoryRouter(routeList) } push(path) { this.router.push(path) } replace(path) { this.router.replace(path) } go(num) { this.router.go(num) } }
const webRouter = new WebRouter({ mode: MODE, routeList: ROUTELIST, })
document.querySelector('.btn-list').addEventListener('click', (e) => { const event = e || window.event if (event.target.tagName === 'LI') { const url = event.target.dataset.url !url.indexOf('/') ? webRouter.push(url) : webRouter.go(url) } })
document.querySelector('.replace-btn').addEventListener('click', (e) => { webRouter.replace('/') })
|
大功告成~