1.vue路由的两种模式

hash模式:
比如 'http://www.baidu.com/#/abc'  hash 的值为 '#/abc'  
它的特点在于:hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,因此改变 hash 不会重新加载页面
但是会触发 onhashchange 事件,所以我们可以监听,然后渲染自己要渲染的组件,达到路由的效果

history模式: 
通过 HTML5 中新增的 pushState() replaceState() 方法
应用于浏览器的历史记录,在已有的 go(),back(),forward() 的基础之上,它们提供了对历史记录进行修改的功能
当它们执行修改时,虽然改变了当前的 URL,但你浏览器不会立即向后端发送请求
我们可以通过 onpopstate 事件,监听 history 的变化,然后渲染自己要渲染的组件,达到路由的效果

2、hash的特点


hash变化会触发网页跳转,即浏览器的前进和后退。

hash 可以改变 url ,但是不会触发页面重新加载(hash的改变是记录在 window.history 中),即不会刷新页面。也就是说,所有页面的跳转都是在客户端进行操作。因此,这并不算是一次 http 请求,所以这种模式不利于 SEO 优化。hash 只能修改 # 后面的部分,所以只能跳转到与当前 url 同文档的 url 。

hash 通过 window.onhashchange 的方式,来监听 hash 的改变,借此实现无刷新跳转的功能。

hash 永远不会提交到 server 端(可以理解为只在前端自生自灭)。

更新视图但不重新请求页面,是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有2种方式:

  • 利用URL中的hash("#");
  • 利用History interfaceHTML5中新增的方法;

vue-routerVue.js框架的路由插件,它是通过mode这一参数控制路由的实现模式的:

const router=new VueRouter({
    mode:'history',
    routes:[...]
})

创建VueRouter的实例对象时,mode以构造参数的形式传入。

src/index.js

export default class VueRouter{
    mode: string; // 传入的字符串参数,指示history类别
  history: HashHistory | HTML5History | AbstractHistory; // 实际起作用的对象属性,必须是以上三个类的枚举
  fallback: boolean; // 如浏览器不支持,'history'模式需回滚为'hash'模式
  
  constructor (options: RouterOptions = {}) {
    
    let mode = options.mode || 'hash' // 默认为'hash'模式
    this.fallback = mode === 'history' && !supportsPushState // 通过supportsPushState判断浏览器是否支持'history'模式
    if (this.fallback) {
      mode = 'hash'
    }
    if (!inBrowser) {
      mode = 'abstract' // 不在浏览器环境下运行需强制为'abstract'模式
    }
    this.mode = mode

    // 根据mode确定history实际的类并实例化
    switch (mode) {
      case 'history':
        this.history = new HTML5History(this, options.base)
        break
      case 'hash':
        this.history = new HashHistory(this, options.base, this.fallback)
        break
      case 'abstract':
        this.history = new AbstractHistory(this, options.base)
        break
      default:
        if (process.env.NODE_ENV !== 'production') {
          assert(false, `invalid mode: ${mode}`)
        }
    }
  }

  init (app: any /* Vue component instance */) {
    
    const history = this.history

    // 根据history的类别执行相应的初始化操作和监听
    if (history instanceof HTML5History) {
      history.transitionTo(history.getCurrentLocation())
    } else if (history instanceof HashHistory) {
      const setupHashListener = () => {
        history.setupListeners()
      }
      history.transitionTo(
        history.getCurrentLocation(),
        setupHashListener,
        setupHashListener
      )
    }

    history.listen(route => {
      this.apps.forEach((app) => {
        app._route = route
      })
    })
  }

  // VueRouter类暴露的以下方法实际是调用具体history对象的方法
  push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    this.history.push(location, onComplete, onAbort)
  }

  replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    this.history.replace(location, onComplete, onAbort)
  }
}
  1. 作为参数传入的字符串属性mode只是一个标记,用来指示实际起作用的对象属性history的实现类,两者对应关系:
modehistory:
        'history':HTML5History;
        'hash':HashHistory;
        'abstract':AbstractHistory;
  1. 在初始化对应的history之前,会对mode做一些校验:若浏览器不支持HTML5History方式(通过supportsPushState变量判断),则mode设为hash;若不是在浏览器环境下运行,则mode设为abstract;
  2. VueRouter类中的onReady(),push()等方法只是一个代理,实际是调用的具体history对象的对应方法,在init()方法中初始化时,也是根据history对象具体的类别执行不同操作

两种模式比较

一般的需求场景中,hash模式与history模式是差不多的,根据MDN的介绍,调用history.pushState()相比于直接修改hash主要有以下优势:

  • pushState设置的新url可以是与当前url同源的任意url,而hash只可修改#后面的部分,故只可设置与当前同文档的url
  • pushState设置的新url可以与当前url一模一样,这样也会把记录添加到栈中,而hash设置的新值必须与原来不一样才会触发记录添加到栈中
  • pushState通过stateObject可以添加任意类型的数据记录中,而hash只可添加短字符串
  • pushState可额外设置title属性供后续使用

history模式的问题

对于单页应用来说,理想的使用场景是仅在进入应用时加载index.html,后续在的网络操作通过ajax完成,不会根据url重新请求页面,但是如果用户直接在地址栏中输入并回车,浏览器重启重新加载等特殊情况。

hash模式仅改变hash部分的内容,而hash部分是不会包含在http请求中的(hash#):

http://oursite.com/#/user/id //如请求,只会发送http://oursite.com/

所以hash模式下遇到根据url请求页面不会有问题

history模式则将url修改的就和正常请求后端的url一样(history不带#)

http://oursite.com/user/id

如果这种向后端发送请求的话,后端没有配置对应/user/idget路由处理,会返回404错误。

Logo

前往低代码交流专区

更多推荐