Vue路由 ---- vue-router

vue-router 中常用的 hash 和 history 路由模式实现原理吗?

Two Point!!!

  • spa页面不能刷新:
    // 1.hash
    // 2.history api

  • url变化显示对应内容:
    // 1.router-view:占位容器
    // 2.数据响应式,current路由 变化触发视图更新;
    响应式得两种实现方式?

    • 方式1:借鸡生蛋 - new Vue({data: {current: '/'}})
    • 方式2:Vue.util.defineReactive(obj, 'current', '/')

hash 模式的实现原理

早期的前端路由的实现就是基于 location.hash 来实现的。其实现原理很简单,location.hash 的值就是 URL 中 # 后面的内容。比如下面这个网站,它的 location.hash 的值为 '#search':

https://www.word.com#search

hash 路由模式的实现主要是基于下面几个特性:
  • URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送;

  • hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换;

  • 可以通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 JavaScript 来对 loaction.hash 进行赋值,改变 URL 的 hash 值;

  • 我们可以使用 hashchange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。

依据配置的路由表进行路由匹配 ---- > routeMap获取需要更新的组件

history 模式的实现原理

HTML5 提供了 History API 来实现 URL 的变化。其中做最主要的 API 有以下两个:history.pushState() 和 history.repalceState()。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录,如下所示:

window.history.pushState(null,null, path);
window.history.replaceState(null,null, path);

history 路由模式的实现主要基于存在下面几个特性:

  • pushState 和 repalceState 两个 API 来操作实现 URL 的变化 ;

  • 使用 popstate 事件来监听 url 的变化,从而对页面进行跳转(渲染);

  • history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面跳转(渲染)。

注意:
  • histroy模式需要后端配合配置;eg: nginx
  • 本地路由需要匹配404页面,路由配置在最后 *;

hash和histrory比较

hash 模式相比于 history 模式的优点:

  • 兼容性更好,可以兼容到IE8
  • 无需服务端配合处理非单页的url地址

hash 模式相比于 history 模式的缺点:

  • 路径多个#,比较丑
  • 导致锚点功能失效
  • 相同 hash 值不会触发动作将记录加入到历史栈中,而 pushState 则可以。

综上所述,当我们不需要兼容老版本IE浏览器,并且可以控制服务端覆盖所有情况的候选资源时,可以使用 history 模式了

手写实现简单vue-router

let Vue;

// 1.实现插件
class VueRouter {
  constructor(options) {
    this.options = options;

    // 数据响应式,current必须是响应式的,这样他变化,使用它的组件就会重新render
    Vue.util.defineReactive(
      this,
      "current",
      window.location.hash.slice(1) || "/"
    );

    // 监控url变化
    window.addEventListener("hashchange", () => {
      this.current = window.location.hash.slice(1);
    });
  }
}

// Vue插件要实现一个install方法
VueRouter.install = function(_Vue) {
  Vue = _Vue;

  // 注册router实例
  // 通过全局混入:Vue.mixin({beforeCreate})
  Vue.mixin({
    beforeCreate() {
      // 仅在根组件创建时执行一次,Vue实例则有该$router
      if (this.$options.router) {
        Vue.prototype.$router = this.$options.router;
      }
    },
  });

  // 注册router-view和router-link
  Vue.component("router-view", {
    render(h) {
      // url => component
      // url
      // window.location.hash
      // router: this.$router
      let component = null;
      const { current, options } = this.$router;
      // 简易的路由表匹配
      const route = options.routes.find((route) => route.path === current);
      if (route) {
        component = route.component;
      }
      console.log(current, options);
      return h(component);
    },
  });
  Vue.component("router-link", {
    props: {
      to: {
        type: String,
        required: true,
      },
    },
    render(h) {
      // xxx
      // xxx
      // JSX写法:  return {this.$slots.default};
      return h("a", { attrs: { href: "#" + this.to } }, this.$slots.default);
    },
  });
};

export default VueRouter;

STRONG

  • 查看vue-router源码,并自己尝试实现嵌套路由

你可能感兴趣的:(Vue路由 ---- vue-router)