记录前端路由遇到的问题

1,062 阅读2分钟

我们在使用 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() 方法。这两个方法应用于浏览器记录栈,在当前已有的 backforwardgo 基础之上,它们提供了对历史记录修改的功能。只是当它们执行修改时,虽然改变了当前的 URL ,但浏览器不会立即向后端发送请求。

优劣

这里引用Vue Router官方的介绍:

vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。 如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 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
  }
});

这样一来,便可以解决上述问题。