说到路由,我们都知道,路由切换无外乎使用hashChange或者是history.pushState, 让我们重新梳理一下这两种模式
Hash模式
- Hash模式基于锚点, 以及onhashchange事件
- hashChange的方式拥有良好的浏览器兼容性, 但是url中多了丑陋的/#/部分
History模式
History模式是基于HTML5中的Hitstory API, history.pushState方法能提供优雅的url,但需要额外的服务端配置解决任意路径刷新问题
- history.pushState() // IE10以后才支持
- history.replaceState()
- history.popState()
两种模式比较
在Vue Router或者React Router中都提供了两种解决方案,供你自己根据业务需求挑选
个人感觉两种都用的比较多,但有一种情况,用history模式会比较好
路由定义如下图:
const route = {
path: '/customer-detail/:customerId',
name: '客户详情',
component: './Customer/CustomerGroupDetail',// 处理公共部分逻辑之类
routes: [
{
path: '/customer-detail/:customerId/base-info',
name: '基本信息',
component: './Customer/CustomerBaseInfo',// 基本信息页
},
{
path: '/customer-detail/:customerId/relation-info',
name: '关联人信息',
component: './Customer/RelationInfo',// 关联人信息页
},
]
}
History模式在服务端配置
1.nginx配置, 打开nginx.conf文件,修改server下的location属性
server {
location / {
try_files $uri $uri/ /index.html;
}
}
try_files: 试着去找一下这个文件 &uri: 当前请求的路径,若找到,直接返回该文件,若找不到,返回单页应用的首页(index.html)
2.nodejs配置, 如下图
const path = require('path')
// 导入处理 history 模式的模块
const history = require('connect-history-api-fallback')
// 导入 express
const express = require('express')
const app = express()
// 注册处理 history 模式的中间件
app.use(history())
// 处理静态资源的中间件,网站根目录 ../web
app.use(express.static(path.join(__dirname, '../web')))
// 开启服务器,端口是 3000
app.listen(3000, () => {
console.log('服务器开启,端口:3000')
})
Vue Router--History模式设计思路
- 通过history.pushState()改变地址栏
- 监听popState()事件
- 根据当前路由地址找到对应组件重新渲染
贴一部分,用History模式实现的简易版VueRouter
let _Vue = null
class VueRouter {
static install(Vue){
//1 判断当前插件是否被安装
if(VueRouter.install.installed){
return;
}
VueRouter.install.installed = true
//2 把Vue的构造函数记录在全局
_Vue = Vue
//3 把创建Vue的实例传入的router对象注入到Vue实例
// _Vue.prototype.$router = this.$options.router
_Vue.mixin({
beforeCreate(){
if(this.$options.router){
_Vue.prototype.$router = this.$options.router
}
}
})
}
constructor(options){
this.options = options
this.routeMap = {}
// observable
this.data = _Vue.observable({
current:"/"
})
this.init()
}
init(){
this.createRouteMap()
this.initComponent(_Vue)
this.initEvent()
}
createRouteMap(){
//遍历所有的路由规则 吧路由规则解析成键值对的形式存储到routeMap中
this.options.routes.forEach(route => {
this.routeMap[route.path] = route.component
});
}
initComponent(Vue){
Vue.component("router-link",{
props:{
to:String
},
render(h){
return h("a",{
attrs:{
href:this.to
},
on:{
click:this.clickhander
}
},[this.$slots.default])
},
methods:{
clickhander(e){
// pushState接收三个参数, state(将来触发popState时传给popState事件的事件对象的一个参数),title,url
history.pushState({},"",this.to)
this.$router.data.current=this.to
e.preventDefault()
}
}
// template:"<a :href='to'><slot></slot><>"
})
const self = this
Vue.component("router-view",{
render(h){
// self.data.current
const cm=self.routeMap[self.data.current]
return h(cm)
}
})
}
initEvent(){
//
window.addEventListener("popstate",()=>{
this.data.current = window.location.pathname
})
}
}
export default VueRouter
Vue Router--Hash模式设计思路
- URL中 # 后面地址作为路径地址
- 监听hashChange事件
- 根据当前路由地址找到对应组件重新渲染