一、路由
1.前端路由
- Hash:使用url中的hash(#后面的参数)来作为路由,通过监听hash变化找到对应组件中内容更新到页面中去。支持所有浏览器。
- History:使用HTML5 History API 和服务器配置。参考官网中HTML5 History模式。有兼容性,支持特定浏览器。
2.后端路由
- 直接访问url,向服务器请求资源。
3.前后端路由区别
- 后端路由向服务器发出请求。
- 前端路由修改视图时,不会向服务器发出请求。
二、hash模式和history模式的区别
1.hash
- 即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算)。比如这个 URL:http://www.baidu.com/#/hello,hash 的值为 #/hello。利用 location.hash和window.addEventListener('hashchange,()=>{})方法获取和监听hash值。它的特点在于:hash 虽然出现在 URL 中,修改hash不会向服务器发送http请求,因此改变 hash 不会重新加载页面。
- 符号#夹杂在 URL 里看起来确实有些不太美丽
- 兼容性好,所有浏览器都支持
- hash 只可添加短字符串
- hash 模式下,仅 hash 符号之前的内容会被包含在请求中,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误
2.history
- 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
- 没有符号#,看起来优雅很多。
- 兼容指定浏览器。
- pushState() 通过 stateObject 参数可以添加任意类型的数据到记录中
- 用户手动输入 URL 后回车,或者刷新(重启)浏览器的时候跳转后刷新或者回跳,会报一个404的错误,找不到指定的路由,所以后端将所有请求都强制重定向到首页,相当于服务端屏蔽了访问资源不存在的情况,而将路由的工作留给客户端自己去处理,这样启用了history模式的前端路由在直接定位到子页面时就不会报错了。
- 当服务端重定向后,如果没有进行SSR的同构路由定制,对于所有路由请求都会返回index.html页面,此时如果需要使用404页面,就需要在客户端路由中设定一个优先级最低的兜底路由,由于优先级的缘故,它不会影响其他精确匹配的路由配置:
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '*', component: NotFoundComponent }
]
})
三、实现一个简单hash路由(没有支持子路由哦~)
class HistoryRoute{
constructor(){
this.current=null
}
}
class vueRouter{
constructor(options){
this.mode=options.mode||'hash';
this.routes=options.routes||[];
this.routesMap=this.createMap(this.routes);
this.history=new HistoryRoute;
this.init();
}
init(){//获取当前current路径
if(this.mode=='hash'){
//自动加#
location.hash?'':location.hash='/'
}
window.addEventListener('load',()=>{
this.history.current=location.hash.slice(1)//获取#后面值
})
window.addEventListener('hashchange',()=>{//监听hash改变
this.history.current=location.hash.slice(1)
})
}
//将routes中路径和组件以键值对关联起来
createMap(routes){
return routes.reduce((memo,current)=>{
memo[current.path]=current.component
return memo
},{})
}
}
vueRouter.install=function(Vue){
if(vueRouter.install.installed)return //判断插件是否已注册
vueRouter.install.installed=true
Vue.mixin({
beforeCreate(){//实现双向数据绑定
if(this.$options && this.$options.router){
this._root=this
this._router=this.$options.router;
Vue.util.defineReactive(this,'current',this._router.history)
}else{
this._root=this.$parent._root
}
//$router不可修改
Object.defineProperty(this,"$router",{
get(){
return this._root._router;
},
})
},
})
Vue.component('router-view',{//注册组件
render(h){
console.log(this._self)
var current=this._self._root._router.history.current
var routesMap=this._self._root._router.routesMap
return h(routesMap[current])//渲染组件
}
})
}
export default vueRouter;
四、总结
- hash 模式和 history 模式都属于浏览器自身的特性,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)结合注册Vue全局插件、注册Vue全局组件(router-view)等技术来实现前端路由。对于一般的 Vue + Vue-Router + Webpack + XXX 形式的 Web 开发场景,用 history 模式即可,只需在后端(Apache 或 Nginx)进行简单的路由配置,同时搭配前端路由的 404 页面支持,毕竟以美为主嘛,哈哈~。