Principle and implementation of Vue router

Today, with the rapid development of the front end, if you can't keep learning all the time, you will be eliminated soon. Share the relevant knowledge of Vue router principle implementation. Make a little progress every day.

1, Vue router Basics

**1,Vue. If the parameter passed in is a parameter of the function: * * directly received by the function; If it is an object, call the install method of the object.

2. When initializing a Vue instance, a router is passed in, and a router is generated in the Vue instance r o u t e and route and route and router attributes: r o u t e in Save Store Yes When front of road from gauge be , The current routing rules are stored in the route, The current routing rules are stored in the route, and the routing instance object is stored in the route. You can call some routing related methods.

**3. Steps for using Vue Router: * * create views, register routing plug-ins, create routing objects and configure routing rules, register router objects, use placeholders in the page, and create links.

4. Dynamic routing:

cosnt routes = [
	{
		// Use dynamic routing
		path: '/detail/:id',
		name: 'Detail',
		// When props is enabled, the parameters in the URL will be passed to the component
		// Receive URL parameters through props in the build
		props: true,
		// Route lazy loading
		component: () => import('../views/Detail.vue')
	}
]

5. How to get route parameters in the component:

① Obtain the data {{$route.params.id}} through the current routing rules. This method is strongly dependent on routing. When using components, there must be a route to pass parameters.

② When props is enabled in the routing rule, the route will pass the parameters in the URL to the corresponding component, and the component can receive the props. This is the same as the value transmission method of parent-child components, which no longer depends on the route. props: ['id']

6. Nested routes:

cosnt routes = [
	// Nested Route 
	{
		path: '/',
		component: Layout,
		children: [
			{
				path: '',
				name: 'Index',
				component: Index
			},
			{
				// Path can use relative path or absolute path
                // path: '/detail/:id',
                path: 'detail/:id',
                name: 'Detail',
                props: true,
                component: () => import('../views/Detail.vue')
			}
		]
	}
]

7. Programming navigation: replace/push/go

this.$router.replace('/login') will not record this history

this.$router.push({ name: 'Detail', params: { id: 1 } })

this.$router.go(-2). If - 1 is passed in, it is equivalent to this$ router. back()

2, Hash mode and History mode

1. Differences between Hash mode and History mode:

Differences in manifestations:

The Hash mode has #, and the Hash number is followed by the routing address

The History mode is an ordinary URL, which needs to be supported by the server

Principle difference:

The Hash pattern is based on anchor points and onhashchange events

The History pattern is based on the History API in HTML5

​ history. Pushstate(), which can only be supported after ie10 (no request will be sent, but the routing address will be changed and recorded in the history)

​ history.replaceState()

2. History mode

The server should return the index of the single page application except for the static resources html

When clicking on a hyperlink:

Click the hyperlink and call history Pushstate() changes the address in the browser's address bar, but does not send a request and stores the address in the history. These are done on the client.

When refreshing the browser:

The browser sends a request to the server. The requested address is the address in the address bar. If the server does not process this address, an error will occur; If the server supports History, when the server judges that the current routing address does not exist, it will index the home page of the single page application Html is returned to the browser. After receiving the page, the browser determines the routing address, and then loads the corresponding component content for rendering

Three. Simulation implementation of Vue Router

1. Vue pre knowledge:

Plug in, mixed in, Vue Observable (), slot, render function, runtime and full version of Vue

2. Implementation principle of Vue Router

Hash mode:

① The content behind # in the URL is used as the path address. If only the address behind # is changed, the browser will not send a request and will record this address in the browser access history;

② Listen for hashchange events. When the hash is changed, the hashchange event will be triggered and the current routing address will be recorded;

③ Find the corresponding component according to the current routing address and re render.

History mode:

① Through history The pushstate () method changes the address bar. It only changes the address and records the routing address without sending a request

② By listening to the pop state event, you can listen to the changes of the browser operation and record the changed address. It will not be triggered when calling pushState or replaceState. The browser's forward and backward buttons or back and forward methods will be triggered

③ Find the corresponding component according to the current routing address and re render

3. Vue Router core code

// Register plug-ins
// Vue.use() internally calls the install method of the incoming object
Vue.use(VueRouter)
// Create routing object
const router = new VueRouter({
	routes: [
		{ name: 'home', path: '/', component: homeComponent }
	]
})
// Create Vue instance and register router object
new Vue({
	router,
	render: h => h(App)
}).$mount('#app')

4. Realization idea

① Create vueroter plug-in and use the static method install

Determine whether the plug-in has been loaded

When Vue is loaded, mount the incoming router object on the Vue instance (Note: only execute once)

② Create vueroter class

Initialization, options, routeMap, data (simplify operation, create Vue instance as responsive data, record the current path)

Create a route map, traverse all route information, and record the mapping of components and routes into the routeMap object

Create router link and router view components

When the path changes, find the corresponding component in the routerMap object through the current path and render the router view

Register the pop state, hashchange and load events. When the routing address changes, re record the current path

5. Code implementation

① Create vueroter plug-in

static install (Vue) {  // When this method is called, the Vue constructor is passed in
    // 1. Determine whether the current plug-in has been installed
    if (VueRouter.install.installed) return
    VueRouter.install.installed = true
    // 2. Record Vue constructor to global variable
    _Vue = Vue
    // 3. Inject the router object passed in when creating the Vue instance into the Vue instance
    // Mixed in, all Vue instances and components will execute this method
    _Vue.mixin({
        beforeCreate() {
            if (this.$options.router) {  // This attribute is only available in the Vue instance option, and the component does not
                _Vue.prototype.$router = this.$options.router
                // Initialization components, routing map and event registration are implemented in sections 3, 4 and 5
                this.$options.router.init()
            }
        }
    })
}

② Implementation constructor

constructor (options) {     // Initialize three properties
    this.options = options
    this.routeMap = {}
    this.data = _Vue.observable({   // The data attribute is responsive and automatically updates the view when the route changes
        current: '/'
    })
}

③ Implement createroutema()

creatRouteMap () {      // Create routing map
    // Traverse all routing rules, parse the routing rules into key value pairs and store them in routeMap
    this.options.routes.forEach(route => {
        this.routeMap[route.path] = route.component
    })
}

④ Implement router link and router view components

// Build versions of Vue include runtime version and full version
// Runtime version: template template is not supported. It needs to be compiled in advance when packaging
// Full version: including runtime and compiler. The volume is about 10KB larger than the runtime version. When the program runs, the template is converted into render function
initComponents () {     // Create two components, router link and router view
    _Vue.component('router-link', {
        props: {
            to: String
        },
        // 1 - full version of Vue -- need to be in Vue config. JS to configure runtimeCompiler: true to automatically parse the template into render function
        // template: "<a :href='to'><slot></slot></a>"
        // 2 - Vue at runtime -- use render function directly
        render (h) {
            // The h function receives three parameters. The first one is to generate the header of the dom element, the second is to set some options, and the third is the content
            return h('a', { 
                attrs: {
                    href: this.to
                },
                on: {
                    click: this.handleClick
                }
            }, [this.$slots.default])
        },
        methods: {
            handleClick(e) {
                // pushState receives three parameters, 1 - event object, 2 - Web page title, 3 - address of hyperlink jump in
                history.pushState({}, '', this.to)
                this.$router.data.current = this.to
                // Cancel the default behavior of a tag to prevent page refresh from sending a request to the server
                e.preventDefault()
            }
        }
    })
    const that = this
    _Vue.component('router-view', {
        render (h) {
            // Find the corresponding component according to the current path and pay attention to this problem
            const component = that.routeMap[that.data.current]
            return h(component)
        }
    })
}

⑤ Implement registration events

There are still some problems when the page is refreshed, backward, forward and the path changes

initEvents() {
    // Get the changed path in the current path and record it again
    window.addEventListener('hashchange', this.onHashChange.bind(this))
    // Refresh button problem
    window.addEventListener('load', this.onHashChange.bind(this))
    // Forward and backward button problem
    window.addEventListener('popstate', this.onHashChange.bind(this))
}

⑥ Implement init()

// It is convenient to initialize when mixing
init() {
    this.creatRouteMap()
    this.initComponents()
    this.initEvents()
}

be careful:

Projects created by Vue cli default to the runtime version of Vue js

If you want to switch to Vue with compiler version JS, you need to modify the Vue cli configuration

Create Vue. From the project root directory config. JS file, add runtimeCompiler

module.exports = {
	runtimeCompiler: true
}

6. Specific source code

let _Vue = null
export default class VueRouter {
    static install (Vue) {  // When this method is called, the Vue constructor is passed in
        // 1. Determine whether the current plug-in has been installed
        if (VueRouter.install.installed) return
        VueRouter.install.installed = true
        // 2. Record Vue constructor to global variable
        _Vue = Vue
        // 3. Inject the router object passed in when creating the Vue instance into the Vue instance
        // Mixed in, all Vue instances and components will execute this method
        _Vue.mixin({
            beforeCreate() {
                if (this.$options.router) {  // This attribute is only available in the Vue instance option, and the component does not
                    _Vue.prototype.$router = this.$options.router
                    this.$options.router.init()
                }
            }
        })
    }

    constructor (options) {     // Initialize three properties
        this.options = options
        this.routeMap = {}
        this.data = _Vue.observable({   // The data attribute is responsive
            current: '/'
        })
    }

    init() {
        this.creatRouteMap()
        this.initComponents()
        this.initEvents()
    }

    creatRouteMap () {      // Create routing map
        // Traverse all routing rules, parse the routing rules into key value pairs and store them in routeMap
        this.options.routes.forEach(route => {
            this.routeMap[route.path] = route.component
        })
    }

    // Build version of Vue
    // Runtime version: template template is not supported. It needs to be compiled in advance when packaging
    // Full version: including runtime and compiler. The volume is about 10KB larger than the runtime version. When the program runs, the template is converted into render function
    initComponents () {     // Create two components, router link and router view
        _Vue.component('router-link', {
            props: {
                to: String
            },
            // 1 - full version of Vue -- need to be in Vue config. JS to configure runtimeCompiler: true to automatically parse the template into render function
            // template: "<a :href='to'><slot></slot></a>"
            // 2 - Vue at runtime -- use render function directly
            render (h) {
                // The h function receives three parameters. The first one is to generate the header of the dom element, the second is to set some options, and the third is the content
                return h('a', { 
                    attrs: {
                        href: this.to
                    },
                    on: {
                        click: this.handleClick
                    }
                }, [this.$slots.default])
            },
            methods: {
                handleClick(e) {
                    // pushState receives three parameters, 1 - event object, 2 - Web page title, 3 - address of hyperlink jump in
                    history.pushState({}, '', this.to)
                    this.$router.data.current = this.to
                    // Cancel the default behavior of a tag to prevent page refresh from sending a request to the server
                    e.preventDefault()
                }
            }
        })
        const that = this
        _Vue.component('router-view', {
            render (h) {
                // Find the corresponding component according to the current path and pay attention to this problem
                const component = that.routeMap[that.data.current]
                return h(component)
            }
        })
    }

    initEvents() {
        // For the problem of path change, retrieve the current path and record it in the current in data
        window.addEventListener('hashchange', this.onHashChange.bind(this))
        // Refresh button problem
        window.addEventListener('load', this.onHashChange.bind(this))
        // Forward and backward button problem
        window.addEventListener('popstate', this.onHashChange.bind(this))
    }
    // Retrieve the current path and record it to the current in data
    onHashChange() {
        this.data.current = window.location.pathname || '/'
    }
}

Keywords: Front-end Vue Vue.js

Added by dmrn on Fri, 18 Feb 2022 09:31:33 +0200