Introduction to the principle of Vue-Router, handwriting your own Vue-Router

Pre-knowledge

Two modes of front-end routing


  1. The content behind # in the Hash mode URL is used as the path address.
    Listen to the HashChange event.
    Find the corresponding component based on the current routing address and re-render it
  2. History mode
    Change the address bar through the history.pushState() method,
    listen to popstate events,
    find the corresponding component based on the current routing address, and re-render

Preparation of handwritten routing

Create a new vue project without vue-router

Create a new router related file in the project

  1. Create a new route folder and create a new index.js under the folder to store routing rules
import Vue from 'vue'
import VueRouter from '../vuerouter'
//从我们自己的router中导入VueRouter
import Index from '../components/Index.vue'
Vue.use(VueRouter)

const routes = [
    {
    
    
        path:'/',
        name:'Index',
        component : Index
    },
    {
    
    
        path:'/about',
        name:'about',
        component: ()=> import('@/views/about.vue')
    },
    {
    
    
        path:'/home',
        name:'home',
        component: ()=> import('@/views/home.vue')
    },
]
const router = new VueRouter({
    
    
    mode:'history',
    base: process.env.BASE_URL,
    routes
})

export default router
  1. Create a new vuerouter folder, and create a new index.js under the folder to store the handwritten router code
    Insert picture description here

  2. Don't forget to quote the router we wrote in main.js

import Vue from 'vue'
import App from './App.vue'
import router from './route'


Vue.config.productionTip = false

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

Start handwriting Vue-Router

First of all, we must clarify what to do by handwriting Vue-router. The following figure is a class diagram of Vue-router, which records in detail what attributes and methods VueRouter needs
Insert picture description here

options: record the object passed in in the constructor (there are routing rules in this object)
routeMap: is an object used to record the correspondence between the routing address and the component, the routing rules will be parsed into the routeMap in the future
data: is an object, There is an attribute current, which is used to record the current routing address. Here, data is used to implement a responsive object.

install method implementation

Through the _ in the class diagram, you can find that install is a static method

let _Vue = null

export default class VueRouter {
    
    

    static install (Vue) {
    
    
        //判断当前插件是否被安装
        if(VueRouter.install.installed){
    
    
            return;
        }
        VueRouter.install.installed = true

        // 把vue构造函数记录到全局变量
        _Vue = Vue
        // 把创建vue实例的时候传入的router对象注入到Vue实例上
        //混入 mixed
        _Vue.mixin({
    
    
            beforeCreate() {
    
    
            if(this.$options.router)
                _Vue.prototype.$router = this.$options.router
            },
        })
    }

}

Implementation of the constructor

    constructor(options){
    
    
        this.options = options

        this.routerMap = {
    
    } // 用于存储解析的router对象
        this.data = _Vue.observable({
    
    
            current:'/'
        })
        // this.init()
    }

In this way, the relevant attributes in the class diagram are realized

CreateRouterMap method implementation

The function of this method is to convert the routing rules passed in the constructor into the form of key-value pairs and store them in the routeMap mentioned above

//遍历所有的路由规则,解析路由规则变为键值对的形式,存储到routermap里
    createRouterMap(){
    
    
        this.options.routes.forEach(route =>{
    
    
            this.routerMap[route.path] = route.component
        })
    }

initComponents method implementation

    initComponents (Vue) {
    
    
        Vue.component('router-link',{
    
    
            props:{
    
    
                to:String
                //接收外部传入的to
            },
            // template:'<a :href="to"><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  _this = this
        Vue.component('router-view', {
    
    
            render(h) {
    
    
                const component = _this.routerMap[_this.data.current]
                return h(component)
            },
        })
    }

initEvent method implementation

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

This method is to load and render components when going back and forward in the browser

Complete handwritten routing code

let _Vue = null

export default class VueRouter {
    
    

    static install (Vue) {
    
    
        //判断当前插件是否被安装
        if(VueRouter.install.installed){
    
    
            return;
        }
        VueRouter.install.installed = true

        // 把vue构造函数记录到全局变量
        _Vue = Vue
        // 把创建vue实例的时候传入的router对象注入到Vue实例上
        //混入 mixed
        _Vue.mixin({
    
    
            beforeCreate() {
    
    
            if(this.$options.router)
                _Vue.prototype.$router = this.$options.router
                // this.$options.router.init()
            },
        })
    }

    constructor(options){
    
    
        this.options = options

        this.routerMap = {
    
    } // 用于存储解析的router对象
        this.data = _Vue.observable({
    
    
            current:'/'
        })
         this.init()
    }
    init(){
    
    
        this.createRouterMap()
        this.initComponents(_Vue)
        this.initEvent()
    }
    //遍历所有的路由规则,解析路由规则变为键值对的形式,存储到routermap里
    createRouterMap(){
    
    
        this.options.routes.forEach(route =>{
    
    
            this.routerMap[route.path] = route.component
        })
    }
    initComponents (Vue) {
    
    
        Vue.component('router-link',{
    
    
            props:{
    
    
                to:String
            },
            // template:'<a :href="to"><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  _this = this
        Vue.component('router-view', {
    
    
            render(h) {
    
    
                const component = _this.routerMap[_this.data.current]
                return h(component)
            },
        })
    }
    initEvent(){
    
    
        window.addEventListener('popstate',()=>{
    
    
            this.data.current = window.location.pathname
        })
    }
}

Reference:
Lagou Education

Guess you like

Origin blog.csdn.net/qq_43377853/article/details/113841827