popstate

When the browser moves forward or backward, it triggers a POPState event and listens for the popState event to display the corresponding component based on the address.

The VueRouter class contains properties and methods

Vue-router can be called to analyze the attributes and methods it contains.

// router.js
import Vue from 'vue'
import VueRouter from '.. /vueroute/index.js'
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
Copy the code
// mian.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

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

From the above call, you can see that the VueRouter class needs the following properties and methods

VueRouter

attribute type use
options Object Used to save the options object passed in when VueRouter was initialized
data.current String Reactive data for storing the routing address of the current page
routeMap Object It is used to store incoming routing rules. The key name is the routing address, and the key value is the corresponding component
methods use
install Static method that implements the VUE plug-in mechanism to register the VueRouter to the VUE
init Centralize the calls to the various initialization methods
initRouteMap Initialize the routeMap object
initComponents Initialize the routerLink and routerView components
initEvents Initialize listening for popState events

Implementation of the install method

let _Vue = null;
export default class VueRouter {
  static install (Vue) {
    // 1. Check whether the plug-in is installed
    if (VueRouter.install.installed) return
    VueRouter.install.installed = true;
    // 2. Record the Vue constructor as a global variable, so that later methods can use Vue
    _Vue = Vue;
    // 3. Inject the router object passed into the Vue instance
    // Blend in to get the Vue instance, i.e. this refers to the unvue instance
    _Vue.mixin({
      beforeCreate () {
        if (this.$options.router) { // Mount only needs to be called once
          // Mount the routing object to the prototype chain of the Vue instance
          _Vue.prototype.$router = this.$options.router
          // Call the initialization method of the route object
          this.$options.router.init()
        }
      }
    })
  }
}
Copy the code

Constructor initialization

  constructor (options) {
    this.options = options // Stored routing rules
    this.routeMap = {} // The routing address corresponds to the component. The key name is the routing address, and the key value is the corresponding component
    // Use the Vue observable to implement responsiveness
    this.data = _Vue.observable({
      current: '/'})}Copy the code

An implementation of the initRouteMap method

  // Initialize the routeMap
  initRouteMap () {
    // Iterate through all the routing rules, parsing the routing rules into key-value pairs, and storing them in the routeMap
    this.options.routes.forEach(route= > {
      this.routeMap[route.path] = route.component
    })
  }
Copy the code

The implementation of the initComponents method

  // Initialize the component
  initComponents (Vue) {
    const _self = this
    // Implement the router-link component
    Vue.component('router-link', {
      props: {
        to: String // It is used to accept the route address to jump to
      },
      render (h) {
        return h ('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.clickHandler
          }
        }, [this.$slots.default])
      },
      methods: {
        clickHandler (e) {
          // Change the browser address bar
          history.pushState({}, ' '.this.to)
          // Update the current address of the storage
          _self.data.current = this.to
          // prevent a tag from jumping by defaulte.preventDefault(); }}})// Implement the router-view component
    Vue.component('router-view', {
      render (h) {
      	// Find the corresponding component based on the current address
        const component = _self.routeMap[_self.data.current]
        // Use vue's render function to render the component
        return h(component)
      }
    })
  }
Copy the code

Implementation of the initEvents method

  // Initialize the event
  initEvents () {
  	// Create a listener event
    window.addEventListener('popstate'.(event) = > {
      // Update the current routing address
      this.data.current = window.location.pathname
    });
  }
Copy the code

The implementation of the init method

  init () {
  	// Initialize the routeMap object
    this.initRouteMap()
    // Create router-link and router-view components
    this.initComponents(_Vue)
    // Initialize listening for popState events
    this.initEvents()
  }
Copy the code

All code for the VueRouter class

let _Vue = null;
export default class VueRouter {
  static install (Vue) {
    // 1. Check whether the plug-in is installed
    if (VueRouter.install.installed) return
    VueRouter.install.installed = true;
    // 2. Record the Vue constructor as a global variable, so that later methods can use Vue
    _Vue = Vue;
    // 3. Inject the router object passed into the Vue instance
    // Blend in to get the Vue instance, i.e. this refers to the unvue instance
    _Vue.mixin({
      beforeCreate () {
        if (this.$options.router) { // Mount only needs to be called once
          // Mount the routing object to the prototype chain of the Vue instance
          _Vue.prototype.$router = this.$options.router
          // Call the initialization method of the route object
          this.$options.router.init()
        }
      }
    })
  }

  constructor (options) {
    this.options = options // Stored routing rules
    this.routeMap = {} // The routing address corresponds to the component. The key name is the routing address, and the key value is the corresponding component
    // Use the Vue observable to implement responsiveness
    this.data = _Vue.observable({
      current: '/'
    })
  }

  init () {
  	// Initialize the routeMap object
    this.initRouteMap()
    // Create router-link and router-view components
    this.initComponents(_Vue)
    // Initialize listening for popState events
    this.initEvents()
  }

  // Initialize the routeMap
  initRouteMap () {
    // Iterate through all the routing rules, parsing the routing rules into key-value pairs, and storing them in the routeMap
    this.options.routes.forEach(route= > {
      this.routeMap[route.path] = route.component
    })
  }
  
  // Initialize the component
  initComponents (Vue) {
    const _self = this
    // Implement the router-link component
    Vue.component('router-link', {
      props: {
        to: String // It is used to accept the route address to jump to
      },
      render (h) {
        return h ('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.clickHandler
          }
        }, [this.$slots.default])
      },
      methods: {
        clickHandler (e) {
          // Change the browser address bar
          history.pushState({}, ' '.this.to)
          // Update the current address of the storage
          _self.data.current = this.to
          // prevent a tag from jumping by defaulte.preventDefault(); }}})// Implement the router-view component
    Vue.component('router-view', {
      render (h) {
      	// Find the corresponding component based on the current address
        const component = _self.routeMap[_self.data.current]
        // Use vue's render function to render the component
        return h(component)
      }
    })
  }

  // Initialize the event
  initEvents () {
  	// Create a listener event
    window.addEventListener('popstate'.(event) = > {
      // Update the current routing address
      this.data.current = window.location.pathname }); }}Copy the code

conclusion

In order to analyze the principle, only the simplest version of VueRouter is implemented. The To attribute of the routerLink component only supports String parameters. You can modify it to match the object type