当前位置 : 主页 > 网络编程 > JavaScript >

Vue Router深扒实现原理

来源:互联网 收集:自由互联 发布时间:2023-02-08
目录 回顾Vue Router的核心代码 代码实现 创建Vue-Router插件 构造函数 完整代码 Vue Router官网 前置知识:插件、slot插槽、mixins混入、render函数、运行时和完整版的Vue 回顾Vue Router的核心代码
目录
  • 回顾Vue Router的核心代码
  • 代码实现
    • 创建Vue-Router插件
    • 构造函数
  • 完整代码

    Vue Router官网

    前置知识:插件、slot插槽、mixins混入、render函数、运行时和完整版的Vue

    回顾Vue Router的核心代码

    // 注册插件
    // Vue.use() 内部调用传入对象的 install 方法
    Vue.use(VueRouter)
    // 创建路由对象
    const router = new VueRouter({
      routes: [
        { name: 'home', path: '/', component: homeComponent }
      ]
    })
    // 创建 Vue 实例,注册 router 对象
    new Vue({
      router,
      render: h => h(App)
    }).$mount('#app')
    

    注意,上述版本为Vue Router 3.x,用法与最新版的有所不同,但理解了其核心设计思路后,再去手写Vue4也是得心应手。

    Vue功能的强大就在于它的插件机制,use可以接受两种参数——函数和对象。如果是函数的话,则会直接调用这个函数,如果是对象的话,则会调用对象的install方法。

    代码实现

    创建Vue-Router插件

    let _Vue = null
    export default class VueRouter {
      static install(Vue) {
        // 1. 判断插件是否已经安装,如果是的话,直接返回
        if (Vue.install.installed) return
        Vue.install.installed = true
        // 2.将Vue的构造函数记录在全局
        _Vue = Vue
        // 3.把创建Vue的实例传入的router对象注入到Vue实例
        _Vue.mixin({
          beforeCreate() {
            // 判断是否是实例,如果是实例就不用添加
            if (this.$options.router) {
              _Vue.prototype.$router = this.$options.router
            }
          },
        })
      }
    }

    构造函数

    constructor(options) {
      this.options = options
      this.routeMap = {}
      this.data = _Vue.observable({
        current: '/'
      })
    }
    

    将options中的路由规则存放到routeMap中

    // 注意,下面的代码只考虑了path和component对应,name同理,也可加上路由元信息,或者遍历加上children,但为便捷及个人水平考虑,并未完整实现
    createRouteMap() {
      // 遍历所有的路由规则,把路由股则解析成键值对的形式,存储到routeMap中
      this.options.routes.forEach(route => {
        this.routeMap[route.path] = route.component
      })
    }
    

    初始化route-link和router-view两个组件

    initComponent(Vue) {
      Vue.component('router-link', {
        props: {
          to: String
        },
        // template: `<a :href="to" rel="external nofollow"  rel="external nofollow" ><slot></slot></a>`
        render(h) {
          return h("a", {
            attrs: {
              href: this.to
            },
            on: {
              click: this.clickhandler
            }
          }, [this.$slots.default])
        },
        methods: {
          clickhandler(e) {
            history.pushState({}, "", this.to)
            this.$router.data.current = this.to
            e.preventDefault();
          }
        },
      })
      const self = this
      Vue.component('router-view', {
        render(h) {
          const component = self.routeMap[self.data.current]
          return h(component)
        }
      })
    }

    浏览器回退、前进时页面同时改变

    initEvent(){
        window.addEventListener("popstate",()=>{
            this.data.current = window.location.pathname
        })
    }
    

    完整代码

    let _Vue = null
    export default class VueRouter {
      constructor(options) {
        this.options = options
        this.routeMap = {}
        this.data = _Vue.observable({
          current: '/'
        })
        this.init()
      }
      static install(Vue) {
        // 1. 判断插件是否已经安装,如果是的话,直接返回
        if (Vue.install.installed) return
        Vue.install.installed = true
        // 2.将Vue的构造函数记录在全局
        _Vue = Vue
        // 3.把创建Vue的实例传入的router对象注入到Vue实例
        _Vue.mixin({
          beforeCreate() {
            // 判断是否是实例,如果是实例就不用添加
            if (this.$options.router) {
              _Vue.prototype.$router = this.$options.router
            }
          },
        })
      }
      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
          },
          // template: `<a :href="to" rel="external nofollow"  rel="external nofollow" ><slot></slot></a>`
          render(h) {
            return h("a", {
              attrs: {
                href: this.to
              },
              on: {
                click: this.clickhandler
              }
            }, [this.$slots.default])
          },
          methods: {
            clickhandler(e) {
              history.pushState({}, "", this.to)
              this.$router.data.current = this.to
              e.preventDefault();
            }
          },
        })
        const self = this
        Vue.component('router-view', {
          render(h) {
            const component = self.routeMap[self.data.current]
            return h(component)
          }
        })
      }
      initEvent() {
        window.addEventListener('popstate', () => {
          this.data.current = window.location.pathname
        })
      }
    }

    到此这篇关于Vue Router深扒实现原理的文章就介绍到这了,更多相关Vue Router内容请搜索易盾网络以前的文章或继续浏览下面的相关文章希望大家以后多多支持易盾网络!

    上一篇:Vue项目中安装使用axios全过程
    下一篇:没有了
    网友评论