我们在使用 Vue 或者 React 等前端渲染时,通常会有 hash 模式和 history 模式两种模式方式。
hash模式
hash (URL中#后面的部分)虽然出现在 URL 中,但不会被包含在 http 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
query方式传参:
this.$router.push({
path:'/xxx'
query:{
id:1
}
})
获取参数:
this.$route.query // {id:1}
此时的页面URL:
http://localhost:8080/#/?id=1
history模式
history 利用了 html5 history interface 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器记录栈,在当前已有的 back、forward、go 基础之上,它们提供了对历史记录修改的功能。只是当它们执行修改时,虽然改变了当前的 URL ,但浏览器不会立即向后端发送请求。
优劣
这里引用Vue Router官方的介绍:
vue-router 默认
hash模式 —— 使用 URL 的hash来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。 如果不想要很丑的hash,我们可以用路由的history模式,这种模式充分利用history.pushStateAPI 来完成 URL 跳转而无须重新加载页面。const router = new VueRouter({ mode: 'history', routes: [...] })当你使用
history模式时,URL 就像正常的 URL,例如http://yoursite.com/user/id,也好看! 不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问http://oursite.com/user/id就会返回 404,这就不好看了。 所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个index.html页面,这个页面就是你 app 依赖的页面。
双问号
在工作中,经常容易碰到非前端开发人员在 hash 模式的链接尾部忘记拼接/#。
像这样:
var id = 1;
window.location.href="http://localhost:8080/?id="+id;
跳转后:
http://localhost:8081/?id=1#/index
this.$route.query // {}
参数部分?id=1出现在了#前边,此时通过this.$route.query便无法获取到id。
不光如此,倘若在页面跳转时又通过 query 传递了参数,像这样:
this.$router.push({
path:'/xxx'
query:{
name: '张三'
}
});
// 实际URL
// http://localhost:8081/?id=1#/index?name=张三
这个时候URL中居然同时出现了两个?。
parseQuery
Vue Route允许我们通过自定义函数去解析URL中的参数。
文档中描述:“提供自定义查询字符串的解析/反解析函数。覆盖默认行为。”
完整代码如下:
import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router);
export default new Router({
routes: [...],
parseQuery (){
var params = {}
var URL = decodeURI(window.location.href)
var startIndex = URL.indexOf('?')
while (startIndex != -1) {
var str = URL.substring(startIndex + 1)
var arr = str.split('&')
for (var i = 0; i < arr.length; i++) {
var kv = arr[i].split('=')
if (kv.length > 1) {
if (kv[1].indexOf('#') > -1) {
kv[1] = kv[1].substring(0, kv[1].indexOf('#'))
}
params[kv[0]] = kv[1]
}
}
startIndex = URL.indexOf('?', startIndex + 1)
}
return params
}
});
这样一来,便可以解决上述问题。