Analyze the principle with a simple Vue router

Understand

With the development of front-end business,
When we write a large-scale vue project, we will use the vue router to distribute the content according to the specified url or hash. Unlike the server sending the request, we can complete the page content switching, reduce the request sent by the server, and make the user jump the page faster and experience better

Doubt

When learning vue router for the first time, most people will have an impression that router link and router view are native tags of vue. But this impression is wrong. vue-router is essentially a plug-in for vue, which is used through Vue.use(VueRouter). Router link and router view are also custom tags implemented by this plug-in.

In this paper, we build a Vue router plug-in to deepen our understanding of its principle

Illustration of url change process

In other words, to implement a simple Vue router, you need to complete the following requirements

Specific operation

Create vue project

vue create my-vue-router

Because it only focuses on the content of Vue router, first use the original Vue router to replace the source file of Vue router

Add Vue router

vue add router

Then the project directory becomes

    my-vue-router
      |- node_modules
      |- public
      |- src
          |- assets
          |- components
              |- HellowWorld.vue
          |- router
              |- index.js
          |- views
              |- About.vue
              |- Home.vue
          |- App.vue
          |- main.js
      |- .gitinore
      |- babel.config.js
      |- package.json
      |- README.md
      |- yarn.lock

In the directory, create a file of myRouter.js to place our source code

Create your own myRouter file

my-vue-router
      |- node_modules
      |- public
      |- src
          |- assets
          |- components
              |- HellowWorld.vue
          |- router
              |- index.js
+             |- myRouter.js            
          |- views
              |- About.vue
              |- Home.vue
          |- App.vue
          |- main.js
      |- .gitinore
      |- babel.config.js
      |- package.json
      |- README.md
      |- yarn.lock

Switch the import file to myRouter.js

At this time, in the content of @ / src/router/index.js, we replace the imported Vue router with our myRouter.js

  import Vue from 'vue'
- import VueRouter from 'vue-router'
+ import VueRouter from './myRouter'
  import Home from '../views/Home.vue'

  Vue.use(VueRouter)

  const routes = [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/about',
      name: 'About',
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
    }
  ]

  const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
  })

  export default router

Here we can see that the code execution process is
Import myrouter.js - > configure routes object - > New vuerouter - > export default

Vue.use() API is used here

Vue.use()

A core api of plug-ins in vue is vue.use()

Install the Vue.js plug-in. If the plug-in is an object, you must provide the install method. If the plug-in is a function, it will be used as the install method. When the install method is called, Vue is passed in as a parameter.
This method needs to be called before new Vue() is called.
When the install method is called multiple times by the same plug-in, the plug-in will only be installed once.

In other words, we have to implement this install method in our own myRouter

demand

  1. Provides a construction class that can use new VueRouter to generate instances
  2. Implement the install method
  3. Listen for url changes and bind current method in two directions
  4. Register user-defined components router link and router view
  5. Realize the transformation from user configured route array to map, and query the route matching objects conveniently and quickly

Realization

let Vue;//Since the user must use the plug-in introduced by vue.use, vue.js will not be introduced into the code to prevent repeated packaging
// Requirement 1 declares a class with a constructor constructor
class VueRouter{
    constructor(options={}){// Constructor
        this.$options=options;// Save configuration items
        this.app = { // Declare a variable with current and complete the two-way binding of the route
            current:"/"
        }
        Vue.util.defineReactive(this.app,'current',this.app.current);//For the interception method of vue, this value will increase get interception to collect dependencies, and set interception to trigger two-way binding
        this.routerMap={}; // Create routerMap of key value mode, which is convenient for using key to quickly find the components to be rendered
        this.init(options); // Execute init method to complete requirements 3,4,5
    }
    init(options={}){
        this.bindBrowserEvents()// Binding browser events
        this.initComponent()//Register router view and router link components
        this.createRouterMap(options.routes)//Create routerMap of key value pattern
    }
    createRouterMap(arr=[]){ // Create routerMap
        arr.forEach(item => {
            this.routerMap[item.path]=item
        });
        //  After processing, the routerMap format is as follows
        //  this.routerMap = {
        //    '/':{
        //      path: '/',
        //      name: 'Home',
        //      component: Home
        //    },
        //    '/about':{
        //      path: '/about',
        //      name: 'About',
        //      component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
        //    }
        //  }
    }
    bindBrowserEvents(){ // hash mode monitoring hashchange method
        window.addEventListener('load',this.onHashChange.bind(this))
        window.addEventListener('hashchange',this.onHashChange.bind(this))
    }
    initComponent(){ // Register custom components RouterLink and RouterView
        Vue.component('RouterLink',{
            props: {
                to: String
            },
            render(h) {
                return h('a',{
                    attrs:{
                        href:'#'+this.to
                    }
                },this.$slots.default)
            },
        })
        Vue.component('RouterView',{
            render:(h)=>{
                const component = this.routerMap[this.app.current].component
                return h(component)
            },
        })
    }
    onHashChange(){ // When the hash changes, change this.app.current 
        window.location.hash = window.location.hash || '/'; // If the hash does not have a value, it will be supplemented by one by default/#/
        if(this.routerMap[window.location.hash.slice(1)]){ // this.app.current = hash value
            this.app.current = window.location.hash.slice(1);
        }else{
            this.app.current = '/';
        }

        // After execution here, routerView will be triggered to re render due to bidirectional binding
    }
}

// Requirement 2 implementation of install method
VueRouter.install = function(_Vue){
  Vue = _Vue; // Because install will be the first step, save the incoming Vue instance to the variable Vue
}

Comments are all written in the code. It can perform simple two-way binding function of route. If you have any questions, you can ask ~ learn from each other~

If you think it's good, you can give it to me github Order a star

Tags: Javascript Vue JSON github

Posted on Mon, 09 Mar 2020 06:04:25 -0400 by dilum