Vue源码学习之VueRouter极简实现

文章内容输出来源:拉勾教育大前端高薪训练营

在拉钩训练营学习已经有一段时间了,感觉这段时间的收获远比自己独自学习强的多,自己学习的时候经常会因为惰性,无法坚持,在这里有班主任时刻关注你的学习进度(感觉对我这种懒人蛮好的),最重要的是有了一个学习的计划,不用无头苍蝇一样东一点西一点,最后什么都没记住。学习都是需要方法和技巧的,在训练营会有专业的老师为你答疑解惑,同时会教你解决问题的思路及方法,让你能够触类旁通。这篇文章主要是Vue源码中VueRouter的模拟实现:

最近在学习使用VueRouter的源码,这里简单介绍下VueRouter的实现

什么是Vue.use

  • 我们在引入一些插件的时候经常需要在main里面用到这个语法
  • Vue.use(function/object),内部如果是函数直接调用,是对象则调用对象的install方法

VueRouter源码

  • VueRouter 是使用Vue.use引用的,所以VueRouter必定会有一个install方法
  • VueRouter分为history, hash,hash模式 基于锚点及onhashchange事件,history模式 基于html5中的historyAPI(pushstate,replacestate)以及popstate

下面是具体代码:

main.js 入口文件

import Vue from 'vue'
import App from './App.vue'
import router from './router' //router中导出的VueRouter实例

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

上面是Vue项目的入口文件,从router中引入的VueRouter的实例,然后作为参数实例化一个Vue实例

Router.js

import Vue from 'vue'
// import VueRouter from 'vue-router'
import VueRouter from '../sourceCode/router' //VueRouter实现的源码
import Home from '../views/Home.vue'

Vue.use(VueRouter)
 const routes = [
 {
   path: '/',
   name: 'Home',
   component: Home
 },
 {
   path: '/about',
   name: 'About',
   component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
 }
]
const router = new VueRouter({
  mode: 'hash',
  base: process.env.BASE_URL,
  routes
})

export default router

上面是vueRouter的具体使用,我们在这获取VueRouter的相关参数

源码具体实现(我们在使用VueRouter时先使用Vue.use引入,执行其中的intsall,然后在导出一个实例化的VueRouter对象)

步骤详解

install方法
  • 1.判断当前插件是否已安装
  • 2.将Vue构造函数记录到全局变量
  • 3.创建Vue实例时传入的router对象注入到所有vue实例,同时初始化 routeMap, component, event,mode等参数
initRouteMap
  • 遍历所有的路由规则,将路由规则解析成键值对 存储到routeMap
initComponents
  • 生成全局组件router-link, router-view
initEvent
  • history模式:当活动历史记录条目更改时,将触发popstate事件。如果被激活的历史记录条目是通过
    history.pushState的调用创建的,或者受到对history.replaceState()的调用的影响,popstate事件的
    state属性包含历史条的状态对象的副本。需要注意的是调用history.pushState()或history.replaceState
    不会触发popstate事件。只有在做出浏览器动作时,才会触发该事件,如用户点击浏览器的回退按钮
    (或者在Javascript代码中调用history.back()或者history.forward()方法)
  • hash模式:当活动历史记录条目更改时,将触发hashchange事件。

…/sourceCode/router.js

let _Vue = null
export default class VueRouter {
    constructor(options) {
        this.options = options
        this.routeMap = {} //路由地址组件键值对
        this.mode = options.mode || 'hash'
        this.data = _Vue.observable({
            current:'/'
        }) //创建响应式对象每当地址变化因为是响应式对象,触发router-view组件的更新
    }
    //Vue的构造函数 args可选参数
    static install (Vue) {
        //1.判断当前插件是否已安装
        if (VueRouter.install.installed) {
            return
        }
        VueRouter.install.installed = true
        //2.将Vue构造函数记录到全局变量
        _Vue = Vue
        //3.创建Vue实例时传入的router对象注入到所有vue实例
        //混入
        _Vue.mixin({ //在每个vue实例内部
            //this指向vue的实例对象
            beforeCreate() {
                if (this.$options.router) {
                    _Vue.prototype.$router = this.$options.router
                    this.$options.router.init() //对应VueRouter实例对象中的init
                }
            },
        })
    }
    initRouteMap() {
        //遍历所有的路由规则,将路由规则解析成键值对 存储到routeMap
        this.options.routes.map(route => {
            this.routeMap[route.path] = route.component
        })
    }
    initComponents(Vue) {//定义全局组件
        let that = this
        Vue.component('router-link', {
            props:{
                to:String
            },
            // this指向的是当前组件vue实例
            render(h) {
                let props = {
                    attrs:{
                        href:this.$router.mode === "hash" ? "/#" + this.to : this.to//hash模式拼接#号
                    },
                };
                if (this.$router.mode === "history") {
                    props.on = {
                        click:this.clickHandle
                    }
                }
                return h('a', props, [this.$slots.default])
            },
            methods: {
                clickHandle(e) {
                    e.preventDefault();
                    history.pushState('', '', this.to)
                    this.$router.data.current = this.to // $router=>VueRouter实例 
                }
            },
        })
        Vue.component('router-view', {
            render(h) { 
                const com = that.routeMap[that.data.current]
                return h(com)
            }
        })
    }
    init() {
        this.initRouteMap()
        this.initComponents(_Vue)
        this.initEvent()
    }
    initEvent () {//定义事件
        if (this.mode === "history") {
            window.addEventListener('popstate', () => {
                this.data.current = window.location.pathname
            })
        } else if (this.mode === 'hash') {
            window.addEventListener('hashchange', () => {
                console.log('hashchange')
                this.data.current = window.location.hash.substr(1)
            })
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值