前端路由浅析
很多传播活动开发过程中经常需要制作一些单页应用。基于种种不可抗原因不能使用 Vue、React 等框架进行开发,所以每次开发时都会当场制作/copy 前人的路由代码。
10 月传播活动中因为时间充裕,便自己实现了简单的路由,以后活动如果需要使用可以继续基于此进行开发。
何为路由
狭义上的路由指根据 url 变化页面也进行相应的跳变;广义上的路由指监听 url 的变化,如果 url 的值与预设值相匹配则会触发预设的回调函数。
Hash or History
Hash
hash 的原始意义指的是页面上的一个位置,比如 https://act.you.163.com/act/static/Dr5VgrU6UG.html#rfMXMkaT 这个页面的 hash 是 #rfMXMkaT
,其具体位置为"办公用品",访问这个地址,浏览器就会直接定位到"办公用品"这个位置。
hash 有一个特性为 - 改变 hash 不会触发网页重载。因此可以利用这个特性对 hash 进行改变,利用 onhashchange 事件进行监听。
使用 hash 的路由一般会让页面 url 变成这样:
http://test.hduzplus.xyz/#page1
http://test.hduzplus.xyz/#page2
http://test.hduzplus.xyz/#page3
History
vue-router、React-Router 等路由框架可以使用 h5 新增的 history api 进行路由变化,监听 window 的 onpopstate 事件进行路由监听。
使用 history 的路由页面 url 会清晰的多。
http://test.hduzplus.xyz/page1
http://test.hduzplus.xyz/page2
http://test.hduzplus.xyz/page3
有一定开发基础的小伙伴可能不能理解这种路由监听方式。比如我的主页是 http://test.hduzplus.xyz/
,为什么访问 http://test.hduzplus.xyz/page1
不是 404 而是进入到路由逻辑内呢?
这实际上是 history 路由方式的一个缺点。在正常情况下服务端的确会返回 404,因此我们得在服务端做处理使其返回我们想要的数据才行。具体配置方式在此不表,其配置的主要思想是将该 host 下 404 页面全部转发到 index.html 中,并由 index.html 内的 js 判断路由条件并触发相应的回调。
<!-- apache 配置demo -->
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
基于 hash 的路由实现
实现非常简单,无非就是注册对象,监听 hashchange,执行相应的函数。
选择使用 hash 方式的路由的原因是因为就活动开发而言,开发者无法直接对服务端进行配置。
实现代码如下
class Router {
constructor(config) {
this.config = config
this.router = {}
this.from = this.to = ''
this.view()
}
get now() {
return window.location.hash.substring(1)
}
register({
path, beforeChange = () => {}, change = () => {}, afterChange = () => {}
}) {
this.router[path] = {
beforeChange, afterChange, change
}
}
go(path) {
if (this.now === path) {
this.render(this.router[this.now])
return
}
window.location.hash = path
}
view() {
this.config.forEach(item => {
this.register(item)
})
window.addEventListener('hashchange', () => {
this.render(this.router[this.now])
})
}
render(obj) {
if (typeof obj === 'undefined' || obj === null) {
return
}
[this.from ,this.to] = [this.to, this.now];
const ret = obj.beforeChange(this.from, this.to)
if (ret === false) {
return
}
obj.change(this.from, this.to)
obj.afterChange(this.from, this.to)
}
}
export default Router
使用方式:
import Router from './Router'
const router = new Router([
{
path: 'page1',
beforeChange: () => {},
change: () => {},
afterChange: () => {}
},
{
path: 'page2',
beforeChange: () => {},
change: () => {},
afterChange: () => {}
},
])
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于