The body of the

Basic usage of vue-router.

    // router/index.js
    import Vue from 'vue'l
    import Router from 'vue-router';

    Vue.use(Router);

    export default newRouter({... });Copy the code
// main.js
import Vue from 'vue';
import router from './router';

new Vue({
	router,
	render: (h) = > h(App),
}).$mount('#app');
Copy the code
<! -- App.vue -->
<div id="nav">
	<router-link to="/">Home</router-link> |
	<router-link to="/about">About</router-link>
</div>
<router-view />
Copy the code

The above code we are very familiar with, do not know if you have such a few questions.

  • Vue.use()What is? What did he do?
  • main.jsWhy do you want to mount itrouter?
  • router-linkrouter-viewWhere do these two components come from?

Please look at the following with the above questions in mind.

Basic knowledge of

Vue.use()

Take a look at the explanation on Vue’s official website.

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

This means that if you want to implement a plug-in, you must implement the install method of the plug-in.

Vue.mixin

Next we need to look at a mixin concept, the Vue global API Vue. Mixin.

Globally register a mixin that affects all Vue instances created after registration. Plug-in authors can use interfuse to inject custom behavior into components. Not recommended for use in application code.

Demand analysis

We do a wave of demand analysis before we start, so that we can better do the next thing.

  • Implement vUE plug-in
  • Parsing routes options
  • Monitoring URL Changes
    • html5 history api /login
    • hash xx.html#/login
  • Implementing global components
    • <router-link>
    • <router-view>

Code implementation

Implement Vue plug-in

Save Vue’s local variables for VueRouter to use.

The reason why VueRouter should be initialized in the beforeCreate declaration cycle is because:

Vue.use will execute the install method of the plugin. The Vue instance does not yet exist, so place the operation on the root component’s beforeCreate.

Ensure that the router is mounted only once on the root component.

let Vue;

class VueRouter {}

Vue.install = function (_Vue) {
	Vue = _Vue;

	Vue.mixin({
		beforeCreate() {
			let router = this.$options.router;
			if(router) { Vue.prototype.$router = router; router.init(); }}}); };Copy the code

Parsing routes options

We want data like this so that we can find the corresponding Component by path.

    {
        '/': {
            path: ' '.component: Index,
            ...
        },
        '/about': {
            path: '/about'.component: About, ... }}Copy the code

After some initialization, we do a simple processing of routes.

    class VueRouter {
        constructor(options) {
            this.$options = options;
            this.routeMap = {};
        }

        init() {
            this.createRouteMap(); . }createRouteMap() {
            this.$options.routes.forEach(route= > {
                this.routeMap[route.path] = route; }}})Copy the code

Monitoring URL Changes

There are a few things to note here.

  • This points to the problem.
  • Make sure current is responsive.
  • Get the part after # to correspond to the component.

Vue is used to make data responsive. As for why Current is responsive, continue to read.

    class VueRouter {
        constructor(options){...this.app = new Vue({
                data: { current: '/'}}); }init(){...this.bindEvents();
        }

        bindEvents() {
            window.addEventListener('hashchange'.this.onHashChange.bind(this));
        }

        onHashChange() {
            this.app.current = window.location.hash.slice(1) | |'/'; }}Copy the code

Implementing global components

Vue.component

  • parameter

    • {string} id
    • {Function | Object} [definition]
  • usage

    Register or get global components. The registration also automatically sets the name of the component with the given ID

    // Register the component, passing in an extended constructor
    Vue.component(
    	'my-component',
    	Vue.extend({
    		/ *... * /}));// Register the component and pass in an option object (automatically call vue.extend)
    Vue.component('my-component', {
    	/ *... * /
    });
    
    // Get the registered component (always return constructor)
    var MyComponent = Vue.component('my-component');
    Copy the code

router-link

The implementation of the router-link component here is simple, just wrapping the A tag.

What we want is something like this:

< the router - link to = "/" > home page < / router - the link > / / converted to < a href = "/" > home page < / a >Copy the code

The following code contains several points of knowledge:

  • renderIn thethisPoints to an instance of the current component.
  • renderYou can actually write it insideJSXYes, but eventually it will beloaderConverted toVNode.
  • hrefIt’s a property, so it’s inattrsIn the water.
  • this.$slotsIt’s about slots,defaultYou can access the contents of the label.
    class VueRouter {...init(){...this.initComponent();
        }

        initComponent() {
            Vue.component('router-link', {
                props: {
                    to: String
                },
                render(h) {
                    return h(
                        'a'.attrs: {
                            href: ` #The ${this.to }`},this.$slots.default]
                    )
                }
            })
        }
    }
Copy the code

createElement

The h function in Render is actually createElement, which returns the famous VNode.

// @returns {VNode}
createElement(
	// {String | Object | Function}
	// An HTML tag name, component option object, or
	Resolve an async function of any of the above. Required fields.
	'div'.// {Object}
	// A data object corresponding to the attribute in the template. Optional.
	{},

	// {String | Array}
	// Child virtual nodes (VNodes), built from 'createElement()',
	// You can also use strings to generate "text virtual nodes". Optional.
	[
		'Write some words first.',
		createElement('h1'.'A headline'),
		createElement(MyComponent, {
			props: {
				someProp: 'foobar',},}),]);Copy the code

router-view

Now to explain why data is reactive:

Whenever reactive data is used in the Render component, a change in the reactive data will render again and the page will refresh.

Because this refers to an instance of the current component, functional components are used. See the official documentation for functional components

The second argument gets parent.$router and we get the router instance.

    initComponent(){... Vue.component('router-view', {
            functional: true.render(h, { parent }) {
                const router = parent.$router;
                return h(router.routeMap[router.app.current].component)
            }
        })
    }
Copy the code

The complete code

let Vue;

class VueRouter {
	constructor(options) {
		this.$options = options;
		this.routeMap = {};
		this.app = new Vue({ data: { current: '/'}}); }init() {
		this.bindEvents();
		this.createRouteMap();
		this.initComponent();
	}

	bindEvents() {
		window.addEventListener('hashchange'.this.onHashChange.bind(this));
	}

	onHashChange() {
		this.app.current = window.location.hash.slice(1) | |'/';
	}

	createRouteMap() {
		this.$options.routes.forEach((route) = > {
			this.routeMap[route.path] = route;
		});
	}

	initComponent() {
		Vue.component('router-link', {
			props: {
				to: String,},render(h) {
				return h('a', { attrs: { href: ` #The ${this.to}`}},this.$slots.default, ]); }}); Vue.component('router-view', {
			functional: true.render(h, { parent }) {
				const router = parent.$router;
				returnh(router.routeMap[router.app.current].component); }}); } } VueRouter.install =function (_Vue) {
	Vue = _Vue;
	Vue.mixin({
		beforeCreate() {
			let router = this.$options.router;
			if(router) { Vue.prototype.$router = router; router.init(); }}}); };export default VueRouter;
Copy the code