Use and principle of VueRouter

In early website development, when we need to request different path content in the page, the server directly produces and renders the corresponding HTML page, and returns it to the client for display

A page has its own URL, or URL

The URL is sent to the server, which matches the URL with the re, and gives it to a Controller for processing

The Controller does all sorts of processing and eventually generates HTML or data that is returned to the front end, which is also good for SEO optimization

But the disadvantage is that the data and logic of the front and back end are mixed, and the maintenance and development are difficult, which is not conducive to the development of the front end

These operations are called back-end routing

With the advent of Ajax, there was a development pattern of front – and back-end separation

At this point, the back end is just responsible for providing the API

The front-end will request files from static resource servers for each request, including HTML+CSS+JS, and then use Javascript to render the resources back from these requests in the front-end

The biggest advantage of this approach is the clarity of responsibility on the front and back ends, with the back end focused on data and the front end focused on interaction and visualization

And when the mobile end (iOS/Android) appears, the back end does not need to do any processing, still use the previous set of API

Vue Router is the official route of vue.js. It is deeply integrated with the vue.js core

Vue-router is based on routes and components

  • Routing is used to set access paths and map paths to components
  • In a vue-Router controlled single-page application, the change of the page path is a component switch.

Install Vue Router: NPM install vue-router@4

Steps to use vue-router

  1. Component that creates a routing component

  2. Configure route mapping: Routes array for component-path mapping relationships

  3. Create the route object with the createRouter and pass in the Routes and History modes

  4. Using routing: through and

    and

<template>
  <div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </div>
  <router-view />
</template>
Copy the code

router/index.js

import { createRouter, createWebHashHistory, createWebHistory } from "vue-router";
import Home from ".. /views/Home.vue";

const routes = [
  {
    path: "/".name: "Home".component: Home,
  },
];

const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

export default router;
Copy the code

main.js

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

createApp(App).use(store).use(router).mount("#app");
Copy the code

A couple of points

  1. Routing components are typically storedpagesFolders, where common components are usually storedcomponentsFolder.
  2. By switching, routing components that are “hidden” are destroyed by default and mounted as needed.
  3. Each component has its own$routeProperty, which stores its own routing information.
  4. The entire application has only one router that can pass through the component$routerProperty is obtained.

1. Default path

By default into the site we want to redirect to a certain path to render the corresponding component

const routes = [
    // path sets the root path: / redirect is the /home path
    { path: "/".redirect: "/home" },
    { path: "/home".component: Home },
];
Copy the code

2.router-link

Router-link actually has many properties that can be configured

To attribute:

  • It’s a string, or it’s an object

The replace property

  • With the replace attribute, when clicked, router.replace() is called instead of router.push().

Active – class attribute

  • Set the class applied after element A is activated. The default class is router-link-active

Exact – active – class attribute

  • When links are precisely activated, the class applied to the rendering is router-link-exact-active by default

The replace property

  • Function: Controls the browser history operation mode during route redirection

  • Browser history can be written in two ways: push and replace. The default is push

  • Push is the append history, and the previous page can be rolled back when the user clicks back

  • Replace replaces the current record

3. Lazy route loading

JavaScript packages can become very large when packaged to build applications, affecting page loads

If we could split the different components into different code blocks and load the routes when they are accessed, it would obviously improve rendering efficiency

const routes = [
    { path: "/".redirect: "/home" },
    // Component can pass in a component or receive a function that returns a Promise; // Component can pass in a component or receive a function that returns a Promise;
    The import function returns a Promise
    { path: "/home".component: () = > import(".. /pages/Home.vue")},];Copy the code

4. Route other attributes

  • Name attribute: Unique name of the routing record
  • Meta attributes: Custom data
const routes = [
  { path: "/".redirect: "/home" },
  {
    path: "/home".component: () = > import(".. /pages/Home.vue"),
    name: "home".meta: {
      name: "yunmu".age: 18,}},];Copy the code

You can name a route to simplify route forwarding

<! - simplified, jump directly by name - > < the router - link: to = "{name:" home "} "> jump < / router - the link > <! - simplify writing with passing parameters - > < the router - link: to = "{name:" home ", the query: {id: 666, the title: "YunMu"}} "> jump < / router - the link >Copy the code

5. Dynamic routing (passing params parameters)

Many times we need to map routes with a given matching pattern to the same component

For example, we jump to different User interfaces with different ids, but we are actually jumping to the same User component

At this point we can use dynamic routing

  1. Configure the route and declare the params parameter to receive

router/index.js

{
  path: "/home".component: Home,
  children: [{path: "news".component: News,
    },
    {
      component: Message,
      children: [{name: "xiangqing".path: "detail/:id/:title".// Use placeholder declarations to receive params arguments
          component: Detail,
        },
      ],
    },
  ],
};
Copy the code
  1. Passing parameters
<! - jump, and they carry a params argument, string to write - > < the router - link: to = "/ home/message/detail / 666 / hello" > jump < / router - the link > <! <router-link :to="{name: 'xiangqing', params: {id: 666, title: 'xiangqing', params: {id: 666, title: },}" > jump </router-link>Copy the code

Note: When a route carries the params parameter, if the object syntax is to, the path configuration item cannot be used. The configuration item must be name.

view/User.vue

<template> <div> This is the User page <! {{$route.params.id}} <! {$route.params.id} <! {{id}} </div> </template> <script> import {useRoute} from "vue-router"; Export default {name: "User", // Configure the route parameters to props: Const Route = useRoute(); ["id"], setup() {// Const Route = useRoute(); console.log(route.params.id); }}; </script>Copy the code

Matching multiple parameters

{
    // For example, the path is /user/123/info/yunmu
    path: "/user/:id/info/:name".component: () = > import(".. /pages/User.vue"),},Copy the code

6.NotFound

Routes that are not matched are usually matched in an error page such as NotFound

$route.params.pathMatch = $route.params.pathMatch

{
    path: "/:pathMatch(.*)".component: () = > import(".. /pages/NotFound.vue"),},Copy the code

Matching rule plus * through $route.params.pathMatch resolves the path to an array

{
    path: "/:pathMatch(.*)*".component: () = > import(".. /pages/NotFound.vue"),},Copy the code

7. Set routine by

The Home and User routes we developed earlier are low-level routes

There might be the Home page itself, and there might be switching back and forth between multiple components

  • For example, the Home contains Message and Shops components that can be switched back and forth within the Home

This is where nesting is needed. Note that the

is also used in Home to hold components that need to be rendered later

router/index.js

{
    path: "/home".name: "home".component: () = > import(/* webpackChunkName: "home-chunk" */ ".. /pages/Home.vue"),
    children: [ // Configure the child route through children
      {
        path: "message".// Do not write: /message here
        component: () = > import(".. /pages/HomeMessage.vue"),}, {path: "shops".// Don't write: /shops
        component: () = > import(".. /pages/HomeShops.vue"),},],},Copy the code

pages/Home.vue

<template> <div> <h2>Home</h2> <router-view /> <router-link to="/ Home /message"> message </router-link> <router-link To = "/ home/shops" > products < / router - the link > < / div > < / template >Copy the code

8. Programmatic routing navigation

Sometimes we want to jump to a page through code without using

jumpToAbout() {
    this.$router.push("/about")
    // An object can also be passed in
    this.$router.push({
        path: "/about"})}Copy the code

In setup we can retrieve the Router object with useRouter to jump to

setup() {
    const router = useRouter();

    const jumpToAbout = () = > {
        router.push("/about");
        // router.push({
        // path: "/about",
        // })
        // router.replace("/about")
    };

    return {
        jumpToAbout,
    };
Copy the code
// Move a record forward as router.forward()
router.go(1);

// Roll back a record that is the same as router.back()
router.go(-1)

// Forward four records
 router.go(4)

// There are not so many records, silent failure
 router.go(100)

router.forward() / / to go forward

router.back() / / back
Copy the code

9. Routing the query pass parameter

  1. Passing parameters
<! -- jump to a string with a query argument --><router-link :to="/home/message/detail? Id = 666 & title = how are you">jump</router-link><! -- jump to and carry the query argument --><router-link 
	:to="{path: '/ home/message/detail, query: {id: 666, the title:' hello '}}"
>jump</router-link><! -- jump to and carry the query argument -->const jumpToAbout = () = > {
    router.push({
        path: "/about".query: {
            name: "yunmu".age: 18}})};Copy the code

Receive parameters

$route.query.name
$route.query.age
Copy the code

10. Cache routing components

  • Effect: Keeps undisplayed routing components mounted and not destroyed.
<keep-alive include="News"> 
    <router-view></router-view>
</keep-alive>
Copy the code

11. Two new lifecycle hooks

  1. Purpose: Two hooks unique to a routing component that capture the active status of a routing component.
  2. Specific name:
    1. activatedTriggered when the routing component is activated.
    2. deactivatedTriggered when the routing component is inactivated.

12. The router – v – slot of the link

In vue-Router3. x, router-link has a tag attribute that determines what element router-Link is rendered to

However, starting with Vue-Router4.x, this attribute is removed

Instead, it gives us a more flexible V-slot way to customize the rendered content

First, we need to use custom to indicate that our entire element is to be customized. If not, the custom content will be wrapped in an A element

Second, we use V-slot to scope the slot to get the values passed to us internally

  • Href: Parsed URL
  • Route: Normalized route object parsed
  • Navigate: The function that triggers the navigation
  • IsActive: indicates the matching status
  • IsExactActive: Indicates whether the match is exact
<router-link to="/home" v-slot="props" custom> <button @click="props.navigate">{{ props.href }}</button> <button </button> <p>{{props. Route}}</p> <span :class="{active: props.isActive }">{{ props.isActive }}</span> <span :class="{ active: props.isActive }">{{ props.isExactActive }}</span> </router-link>Copy the code

Router-view also provides us with a slot that can be used with
and

components to wrap your routing components

Component: Component to render

<router-view v-slot="props">
    <transition name="yun">
        <keep-alive>
            <component :is="props.Component"></component>
        </keep-alive>
    </transition>
</router-view>
Copy the code
.yun-active {
  color: red;
}

.yun-enter-from..yun-leave-to {
  opacity: 0;
}

.yun-enter-active..yun-leave-active {
  transition: opacity 1s ease;
}
Copy the code

13. Configure the props for routing

Function: Make it easier for components to receive parameters

{
  name: "xiangqing".path: "detail/:id".component: Detail,

  // The first way is that the props value is an object, and all combinations of key-values in this object are passed to the Detail component through the props
  // props:{a:900}

  // If the parameter is true, pass all params parameters received through the route to the Detail component through props
  // props:true

  // The third way is that the props value is a function. Each set of key-values returned by this function is passed to the Detail component through props
  props(route) {
    return {
      id: route.query.id,
      title: route.query.title, }; }};Copy the code

14. Dynamically add and delete routes

In some cases, different routes are registered according to different user permissions

In this case, we can use the addRoute method to dynamically add routes

Dynamically Adding routes

const categoryRoute = {
  path: "/category".name:"category".component: () = > import(".. /pages/Category.vue"),};// Add a top-level routing object
router.addRoute(categoryRoute);
Copy the code
// Add a secondary route object. The first parameter is the route name and the second parameter is the component to be added
router.addRoute("home", {
  path: "moment".component: () = > import(".. /pages/HomeMoment.vue")});Copy the code

Dynamically Deleting routes

There are three ways to delete a route:

  1. Example Add a route with the same name
  2. The name of the route is passed in using router.removeRoute
  3. Use the return value function of the router.addRoute method

Routes are supplemented by other methods

  • Router.hasroute () : checks whether a route exists
  • Router.getroutes () : Gets an array of all routing records

15. Route navigation guard

The navigation guard provided by vue-Router is used to control the permission of routes

Categories: Global guard, exclusive guard, component inside guard

Global front guard

Router. beforeEach is called back when navigation is triggered and has two arguments

  • To: Route object to be entered
  • From: Outgoing Route Route object

The return value

  • False: Cancel the current navigation
  • No return or undefined: default navigation
  • Returns a routing address
    • It can be a string path
    • It can be an object that contains information such as Path, Query, and params

Optional third parameter: next

  • In Vue2 we use the next function to decide how to jump, but it’s easy to call next multiple times
  • But in Vue3 we control by returning a value, and the next function is no longer recommended
// Global front-guard: executed at initialization and before each route switch
router.beforeEach((to, from, next) = > {
  console.log("beforeEach", to, from);
  if (to.meta.isAuth) {
    // Determine whether permission control is required for the current route
    if (localStorage.getItem("name") = = ="yunmu") {
      // Specific rules for permission control
      next(); / / release
    } else {
      alert("No permission to view");
      // next({name:"home"})}}else {
    next(); / / release}});// Global post-guard: executed at initialization and after each route switch
router.afterEach((to, from) = > {
  console.log("afterEach", to, from);
  if (to.meta.title) {
    document.title = to.meta.title; // Change the title of the page
  } else {
    document.title = "vue_test"; }});Copy the code

Login Guard function

  • For example, when we complete a feature, we can only see other pages after logging in

login.vue

<script> import { useRouter } from "vue-router"; export default { setup() { const router = useRouter(); const loginClick = () => { window.localStorage.setItem("token", "why"); router.push({ path: "/home", }); }; return { loginClick, }; }}; </script>Copy the code

router/index.js

router.beforeEach((to, from) = > {
  if(to.path ! = ="/login") {
    const token = window.localStorage.getItem("token");
    if(! token) {return "/login"; }}});Copy the code

Other navigation guards

Vue also provides a number of other guard functions, all of which are designed to give us callbacks at any given moment, giving us more control over the flow or functionality of the program

Navigation guard | Vue Router (vuejs.org)

Complete navigation parsing flow:

  1. Navigation triggered
  2. Called in a deactivated componentbeforeRouteLeaveThe guards
  3. Call globalbeforeEachThe guards
  4. Called in a reused componentbeforeRouteUpdateGuard (+ 2.2)
  5. Called in the routing configurationbeforeEnter
  6. Parse the asynchronous routing component
  7. Called in the active componentbeforeRouteEnter
  8. Call globalbeforeResolveGuard (+ 2.5)
  9. Navigation confirmed
  10. Call globalafterEachhook
  11. Triggering DOM updates
  12. callbeforeRouteEnterGuard passnextThe created component instance is passed in as an argument to the callback function

16.Hash and History modes

1. Differences in expression forms

  • Hash mode: http://localhost/#/detail? id=1234
  • The History mode: http://localhost/detail/1234

History is prettier by comparison

2. Differences in principles

  • The Hash pattern is based on the anchor point (#), essentially changedwindow.location.hrefIf you change the URL without refreshing the page, the hash value is not included in the HTTP request, that is, the hash value is not brought to the server. However, if the address is shared through a third-party mobile app in the future, if the APP is strictly verified, the address will be marked as illegal.
  • The History mode is based on the History API in HTML5. There are six modes that change the URL without refreshing the page, which is slightly less compatible than the Hash mode.
    • ReplaceState: replaces the original path
    • PushState: Uses the new path
    • PopState: rollback of a path
    • Go: Changes the path forward or backward
    • Forward: changes the path forward
    • Pback: Changes the path backwards
<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Hash pattern</title>
  </head>
  <body>
    <div id="app">
      <a href="#/home">home</a>
      <a href="#/about">about</a>

      <div class="content">Default</div>
    </div>

    <script>
      const contentEl = document.querySelector(".content");
      window.addEventListener("hashchange".() = > {
        switch (location.hash) {
          case "#/home":
            contentEl.innerHTML = "Home";
            break;
          case "#/about":
            contentEl.innerHTML = "About";
            break;
          default:
            contentEl.innerHTML = "Default"; }});</script>
  </body>
</html>
Copy the code
  • The content after # in the URL is the path address
  • Listen for the Hashchange event
  • Find the corresponding component based on the current routing address and re-render it
<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>The history mode</title>
  </head>
  <body>
    <div id="app">
      <a href="/home">home</a>
      <a href="/about">about</a>

      <div class="content">Default</div>
    </div>

    <script>
      const contentEl = document.querySelector(".content");

      const changeContent = () = > {
        switch (location.pathname) {
          case "/home":
            contentEl.innerHTML = "Home";
            break;
          case "/about":
            contentEl.innerHTML = "About";
            break;
          default:
            contentEl.innerHTML = "Default"; }};const aEls = document.getElementsByTagName("a");
      for (let aEl of aEls) {
        aEl.addEventListener("click".(e) = > {
          e.preventDefault();

          const href = aEl.getAttribute("href");
          // history.pushState({}, "", href);
          history.replaceState({}, "", href);

          changeContent();
        });
      }

      window.addEventListener("popstate", changeContent);
    </script>
  </body>
</html>
Copy the code
  • Change the address bar with the history.pushState () method (no request is sent to the server, but the URL is recorded in History)
  • Listen for popState events
  • Find the corresponding component based on the current routing address and re-render it

3. Use of History mode

  • History requires server support
  • In a single page application, the server does not have an address such as www.test.com/login.
  • The server should return single-page application index.html for all but static resources

Node.js server configuration

const path = require("path");
// Import the module that handles history mode
const history = require("connect-history-api-fallback");
/ / import express
const express = require("express");

const app = express();
// Key: Register middleware that handles the history pattern
app.use(history());
// Static resource processing middleware, website root directory.. /web
app.use(express.static(path.join(__dirname, ".. /web")));

// Start the server on port 3000
app.listen(3000.() = > {
  console.log("Server on, port: 3000");
});
Copy the code

Nginx server configuration

#Start the
start nginx
#restart
nginx -s reload
#stop
nginx -s stop
Copy the code

nginx.conf

http: {
	server: {
		location / {
			root html;
			index index.html index.htm;
			If you can't find it, return to home page
			try_files$uri $uri/ /index.html; }}}Copy the code

17. Implement your own Vue-Router

A build of Vue

  • Runtime version: Does not support template templates and is compiled ahead of time when packaging is required

Using the render function

Vue.component("router-link", {
  props: {
    to: String,},render(h) {
    return h(
      "a",
      {
        attrs: {
          href: this.to,
        },
      },
      [this.$slots.default]
    );
  },
  // template: '<a href="to"><slot></slot></a>'
});
Copy the code
  • The full version: contains the runtime and compiler, is about 10K larger than the runtime version, and converts the template to the render function when the program runs

Add a file in the project root directory: vue.config.js

module.exports = {
  // Complete version of Vue (with compiler version)
  runtimeCompiler: true
}
Copy the code

Simulate the implementation of VueRouter’s History mode

Implementation approach

  • Create the LVueRouter plug-in, static install
    • Create the LVueRouter plug-in, static install
    • Create the LVueRouter class by mounting the incoming Router object to the Vue instance when the Vue is loaded (note: only once)
  • Initialization, options, routeMap, app(to simplify operations, create Vue instances as responsive data to record the current path)
  • NitRouteMap () iterates through all the routing information, recording the mapping of components and routes into the routeMap object
  • Register a POPState event to re-record the current path when the routing address changes
  • Create router-link and router-view components
  • When the path changes, find the corresponding component in the routerMap object using the current path and render the Router-View

Create the LVueRouter plug-in

export default class VueRouter {
    static install (Vue) {
        // Return if the plug-in is already installed
        if (VueRouter.install.installed && _Vue === Vue) return
        VueRouter.install.installed = true
        _Vue = Vue
        Vue.mixin({
            beforeCreate () {
                // Determine whether the Router object is already mounted to the Vue instance
                if (this.$options.router) {
                    // Inject the Router object into the Vue instance
                    _Vue.prototype.$router = this.$options.router
                }
            }
        })
    }
}
Copy the code

Implement LVueRouter – constructor

constructor (options) {
    this.options = options
    // Record the path and the corresponding component
    this.routeMap = {}
    this.app = new _Vue({
        data: {
            // The current default path
            current: '/'}})}Copy the code

Implement LVueRouter – initRouteMap()

initRouteMap () {
    // routes => [{ name: '', path: '', component: }]
    // Traverses all routing information and records the mapping between paths and components
    this.options.routes.forEach(route= > {
        // Record the mapping between paths and components
        this.routeMap[route.path] = route.component
    })
}
Copy the code

Implement LVueRouter class – register events

initEvents () {
    // When the path changes, retrieve the current path and record it to current
    window.addEventListener('hashchange'.this.onHashChange.bind(this))
    window.addEventListener('load'.this.onHashChange.bind(this))
}
onHashChange () {
    this.app.current = window.location.hash.substr(1) | |'/'
}
Copy the code

Implement LVueRouter class – router-link and router-view components

initComponents () {
    _Vue.component('RouterLink', {
        props: {
            to: String
        },
        // Vue.js with a compiler version is required
        // template: "<a :href='\"#\" + to'><slot></slot></a>"
        // Use the runtime version of vue.js
        render (h) {
            return h('a', {
                attrs: {
                    href: The '#' + this.to
                }
            }, [this.$slots.default])
        }
    })
    const self = this
    _Vue.component('RouterView', {
        render (h) {
            // Find the component based on the current path
            const component = self.routeMap[self.app.current]
            return h(component)
        }
    })
}
Copy the code

Note: Vue-CLI created projects use the runtime version of vue.js by default, with no compiler

Implement LVueRouter – init()

init () {
    this.initRouteMap()
    this.initEvents()
    this.initComponents()
}
Init () is called in the install() method of the plug-in
if (this.$options.router) {
    _Vue.prototype.$router = this.$options.router
    // Call init when the plug-in is initialized
    this.$options.router.init()
}
Copy the code

Vuerouter/index.js

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 to the global variable
    _Vue = Vue;
    // 3. Inject the router object passed into the Vue instance
    / / with
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router;
          this.$options.router.init(); }}}); }constructor(options) {
    this.options = options;
    this.routeMap = {};
    // _vue. observable creates a responsive object
    this.data = _Vue.observable({
      current: "/"}); }init() {
    this.createRoutMap();
    this.initComponents(_Vue);
    this.initEvent();
  }

  createRoutMap() {
    // Iterate over all the routing rules, parse the routing rules into key-value pairs, and store them in the routeMap
    this.options.routes.forEach((route) = > {
      this.routeMap[route.path] = route.component;
    });
  }

  initComponents(Vue) {
    Vue.component("router-link", {
      props: {
        to: String,},render(h) {
        return h(
          "a",
          {
            attrs: {
              href: this.to,
            },
            / / event
            on: {
              click: this.clickHandler,
            },
          },
          [this.$slots.default]
        );
      },
      methods: {
        clickHandler(e) {
          history.pushState({}, "".this.to);
          this.$router.data.current = this.to; e.preventDefault(); }},// template: '<a href="to"><slot></slot></a>'
    });
    const self = this;
    Vue.component("router-view", {
      render(h) {
        const component = self.routeMap[self.data.current];
        returnh(component); }}); }initEvent() {
    window.addEventListener("popstate".() = > {
      this.data.current = window.location.pathname; }); }}Copy the code

Emulate the implementation of VueRouter’s Hash pattern

import Vue from "vue";
console.dir(Vue);
let _Vue = null;
export default class VueRouter {
  // Implement vUE plug-in mechanism
  static install(Vue) {
    //1 Check whether the current plug-in is installed
    if (VueRouter.install.installed) {
      return;
    }
    VueRouter.install.installed = true;
    //2 Record the Vue constructor globally
    _Vue = Vue;
    //3 Inject the Router object passed in to create the Vue instance
    // _Vue.prototype.$router = this.$options.router
    / / with
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router; }}}); }// Initialize the property
  constructor(options) {
    this.options = options; // options records the object passed by the constructor
    this.routeMap = {}; // routeMap maps routing addresses to components
    Observable Data is a reactive object
    this.data = _Vue.observable({
      current: "/".// Current routing address
    });
    this.init();
  }

  // Call createRouteMap, initComponent, initEvent
  init() {
    this.createRouteMap();
    this.initComponent(_Vue);
    this.initEvent();
  }

  // It is used to initialize the routeMap attribute, and the routing rules are converted to key-value pairs
  createRouteMap() {
    // Go through all the routing rules and parse the routing rules into key-value pairs and store them in the routeMap
    this.options.routes.forEach((route) = > {
      this.routeMap[route.path] = route.component;
    });
  }

  // Used to create router-link and router-view components
  initComponent(Vue) {
    / / the router - link component
    Vue.component("router-link", {
      props: {
        to: String,},// render -- can be used directly in vue runtime version
      render(h) {
        // h(selector (tag name), attribute, content of a generated tag)
        return h(
          "a",
          {
            attrs: {
              href: "#" + this.to,
            },
            // Register events
            // on: {
            // click: this.clickHandler // Click event
            / /},},this.$slots.default]
        ); // this.$slot.default Default slot}});/ / the router - the view components
    const self = this; // This points to the instance of vueRouter
    Vue.component("router-view", {
      render(h) {
        // Obtain the component corresponding to the current routing address based on the mapping in routerMap
        const component = self.routeMap[self.data.current];
        returnh(component); }}); }// To register the hashchange event
  initEvent() {
    window.addEventListener("hashchange".() = > {
      this.data.current = this.getHash();
    });
    window.addEventListener("load".() = > {
      if (!window.location.hash) {
        window.location.hash = "# /"; }}); }getHash() {
    return window.location.hash.slice(1) | |"/"; }}Copy the code

Router/index.js

import VueRouter from ".. /vuerouter";
Copy the code