preface

Vue surrounding ecological of official documentation is brushed again recently, because before learning are watching video with the document, but largely through video learning, so it doesn’t understand a lot of knowledge, since the last time to brush the Vuex official documentation is realized through the benefits of a document, learning a foreign technology in the “learning” after the best or go to the official documentation, In this way, you will have a thorough understanding of this technology and a comprehensive knowledge point. Therefore, after brushing Vuex documents, I wrote an article called “In-depth Vuex Best Practices”, and then spent two days (no time for scratching at work, I studied at night) brushing vuE-Router official documents, so I have this article. Therefore, there will be an article about the configuration of VUe-CLI in the future, so the whole article is mainly from a practical perspective. In the next part, I will try to implement the core part of VUe-Router, and finally interpret the source code of the core function

Online humble, if you think this article is helpful to you welcome everyone to click 👻

Introduction to the

Vue-router is the official vue. js route manager. Its deep integration with the vue.js core makes building a single page application a breeze

Let’s start with two things

  • Single Page Application (SPA)
  • Route manager

Single page application

Single-page applications limit all activity to a Single Web page, loading the appropriate HTML, JavaScript, and CSS only when the Web page is initialized. Once the page is loaded, SPA does not reload or redirect the page because of user actions. Instead, JavaScript is used to dynamically transform HTML content to enable UI interaction with the user.

Route manager

The route manager here is not the hardware router in our daily life, the route here is the single page application (SPA) path manager, is to solve the vue. js single page application can not be linked to jump, we through the path of the way to manage different pages

After understanding the problems that vue-Router solves, we began to learn some of the functions that vue-Router commonly uses in projects

  • Nested routing/viewing diagrams
  • Modular, component-based routing configuration
  • Route parameters, queries, and wildcards
  • Fine-grained navigation control

start

Let’s start by looking at some of the functions of the Vue-Router:

  • Dynamic route matching
  • Embedded routines by
  • Declarative/programmatic navigation
  • Name route/name view
  • Redirects and aliases
  • Routing components pass parameters

The addresses of all the sample repositories in this article are given at the end of this article

Dynamic route matching

router.js

import Vue from 'vue' / / into the Vue
import Router from 'vue-router' Vue / / in the router
import Home from '@/pages/Home' // Import the hello.vue component from the root directory
 
// Vue uses Router globally
Vue.use(Router)

/* Build a single page application using vue.js + Vue-router, as long as we compose our application by combining the components, we introduce vue-router, as long as we map the components to routes, telling Vue-router where to render them */

let routes = [ // Configure routing, which is an array
  { // Each link is an object
    path: '/'.// Link the path
    name: 'Home'.// Route name,
    component: Home // The corresponding component template
  },
  // Dynamic path parameters start with a colon
  { path: '/user/:username'.// Dynamic routing
    component: () = > import('.. /pages/User1'), // To load the components corresponding to the route on demand, you need to download polyfill compatible with ES6 syntax
  },
  {   // Multisegment path parameters
    path: '/user/:id/post/:post_id'.// Dynamic routing
    component: () = > import('.. /pages/User2'), // To load the components corresponding to the route on demand, you need to download polyfill compatible with ES6 syntax},]export default new Router({
  routes
})
Copy the code

User1

This component is displayed when the user accesses /#/user/ XXX

<template>
  <div class="User1">User1 - Single path parameter</div>
</template>
Copy the code

User2

/#/user/ XXX /post/ XXX

<template>
  <div class="User2">User2 - Multisegment path parameter route</div>
</template
Copy the code

So how do we know which dynamic parameter route the user is accessing? This is the time to respond to changes in the routing parameters

Two ways: watch (monitor changes) $route object, beforeRouteUpdate navigation guard

Add the following code to user1.vue

<template>
  <div class="User1">
    <! The route attribute can be obtained from the router object. This way, the route attribute can be obtained from the router object.User1 -{{$route.params.username}} Single path parameter</div>
</template>

<script>
export default {
  name: 'User1'.// Listen to route object mode
  watch: {
    $route (to, from) {
      this.$message.success(`watch -> ${to.path}.The ${from.path}`)}},// Vue2.2 introduces navigation guards that are called when route parameters change
  beforeRouteUpdate (to, from, next) {
    this.$message.info('Navigation Guard ->${to.path}.The ${from.path}`)
    // Be sure to call Next to continue parsing the routing component in the next pipeline
    next()
  }
}
</script>
Copy the code

demo

Note that the above ck->ks route parameter changes are heard in both ways, we can do some operations in these two functions when the route state changes

Routing components pass parameters

In the

template, the $router.prams. Username parameter passed by the route is already highly coupled to its corresponding route, limiting its flexibility. We can use props to decouple the component from the route

There are three ways to pass the routing component parameter:

  • The Boolean model
  • Object pattern
  • The function mode

code

router.js

import Vue from 'vue'
import Router from 'vue-router'
import home from '@/pages/Home'

Vue.use(Router)

let routes = [
  {
    path: '/'.name: 'Home'.component: home
  },
  {  // Dynamic path parameters start with a colon
    path: '/user1/:username'.// Dynamic routing
    component: () = > import('.. /pages/User1'),
    props: true  // Boolean mode: if props is set to true, rout. params will be set as a component property.
  },
  { 
    path: '/user2'.component: () = > import('.. /pages/User2'),
    props: {username: 'ck'} // Object mode: only static routes are valid and the parameters are write-dead
  },
  {
    path: '/user3/:username'.component: () = > import('.. /pages/User3'),
    // Return a parameter in the user URL such as /user3? Username ='ck' => {username: 'ck'
    props: (route) = > ({username: route.query.username}) // Function mode}]export default new Router({
  routes
})
Copy the code

User1

The Boolean model

<template>
  <div class="User1">
    User1 -{{username}} 
  </div>
</template>

<script>
export default {
  name: 'User1'.props: ['username']  // Use props to get the parameters that the route passes to the corresponding component
}
</script>
Copy the code

User2

Object pattern

<template>
  <div class="User2">
    User2 - {{username}} 
  </div>
</template>

<script>
export default {
  name: 'User2'.props: ['username']  // Use props to get the parameters that the route passes to the corresponding component
}
</script>
Copy the code

User3

The function mode

<template>
  <div class="User3">
    User3 - {{username}}
  </div>
</template>

<script>
export default {
  name: 'User3'.props: ['username']  // Use props to get the parameters that the route passes to the corresponding component
}
</script>
Copy the code

demo

From above we can see that because user2 is a static route, it does not support dynamic parameters and the parameters passed by its corresponding routing component are also written dead

Embedded routines by

Real-world application interfaces are typically composed of multiple layers of nested components. Similarly, the segments of the dynamic path in the URL correspond to nested layers of components in a certain structure, such as:

/user/ck/profile                     /user/ks/posts
+------------------+                  +-----------------+
| User             |                  | User            |
| +--------------+ |                  | +-------------+ |
| | Profile      | |  +------------>  | | Posts       | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+
Copy the code

router.js

import Vue from 'vue'
import Router from 'vue-router'
import home from '@/pages/Home'

Vue.use(Router)

let routes = [
  {
    path: '/'.name: 'Home'.component: home,
  },
  {
    path: '/user/:username'.// Dynamic routing
    name: 'User'.component: () = > import('.. /components/User'),
    children: [{// If '/user/:username/profile' matches successfully, the UserProfile will be rendered in the 
      
        of the user
      
        path: 'profile'.// Can match /user/ks/profile
        name: 'Profile'.component: () = > import('.. /components/Profile')}, {path: '/user/:usrname/posts'.// we can match /user/ks/posts, but we can match /user:username dynamic component to posts
        name: 'Posts'.component: () = > import('.. /components/Posts')}, {path: ' '.name: 'UserHome'./ / when/user / : username matching success, such as/user/ks | | / user/ck
        // The UserHome is rendered in the User 
      
        component: () = > import('.. /components/UserHome')},]}, {path: '/footer'.name: 'Foo'.component: () = > import('.. /components/Footer')}]export default new Router({
  routes
})
Copy the code

demo

Declarative/programmatic navigation

declarative programmatic
<router-link :to="..." replace> router.replace(...)
<template>
  <div class="home">
       <! -- declarative -->
    <router-link
  	  to="footer"
      tag="button"
    >
        to footer
    </router-link>  
      
    <! -- program -->
    <button @click="$router.push('footer')">String - The way to write the route path</button>
    <button @click="$router.push({path: '/footer'})">Object - The way to write paths</button>
    <button @click="$router.push({name: 'Foo', params: {'userId': '123'}})">Name and params-Write route name to carry parameters</button>
    <button @click="$router.push({path: '/footer', query: {'userId': '456'}})">Queyr and path - Write the way routing paths carry parameters</button>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'home',
  data () {
    return{}},methods: {}}</script>
<style>
button {
  display: block;
}
</style>
Copy the code
  • router.push(location, onComplete? , onAbort?)
  • router.replace(location, onComplete? , onAbort?)

These two methods are the same, the only difference is that push generates routing history, while repalce does not, which is consistent with the history in window

<! -- router-go -->
<template>
     <button @click="goForward">Go (1)- One step forward</button>
    <button @click="goBack">Go (-1)- Take a step back</button>
    <button @click="gogogo">Go (100)- One white step forward</button>   
 </template>

<script>
 export default {
    name: 'home'
  	methods: {
        goForward () {
          // Forward from the historical route is equivalent to window.history.forward
          this.$router.go(1);
        },
        goBack () {
              // Taking a step back from the historical route is equivalent to window.history.back
              this.$router.go(-1);
        },
        gogogo () {
              // If there are not 100 steps in the historical route, nothing will be done
              this.$router.go(100); }}}</script>
Copy the code

demo

Named route/named view/redirection and alias

router.js

import Vue from 'vue'
import Router from 'vue-router'
import UserSettings from '@/pages/UserSettings'

Vue.use(Router)

let routes = [
  {
    path: '/'.redirect: '/settings' / / redirection
  },
  {
    path: '/settings'.name: 'Settings'.// Name the route
    alias: '/a'.// If the url accesses /a ->, the Settings component is also accessed, but the route matches /a, as if the user were accessing /a
    // You can also configure the named view on the top-level route
    component: UserSettings,
    children: [{path: 'emails'.component: () = > import('.. /pages/UserEmails')}, {path: 'profile'.components: {
          default: () = > import('.. /pages/UserProfile'),
          helper: () = > import('.. /pages/UserProfilePreview')}}]}]export default new Router({
  routes
})
Copy the code

UserSetttings

<template>
  <div class="UserSettings">
    <h1>User Settings</h1>
    <NavBar/>
    <router-view/>
    <! -- Name the view -->
    <router-view name="helper"/>  
  </div>
</template>

<script>
import NavBar from '.. /components/NavBar'
export default {
  name: 'UserSettings'.components: {
    NavBar
  }
}
</script>
Copy the code

Through the above study, I believe that you have held the functions commonly used by Vue-Router in the project. Now let’s start to learn the navigation guard of Vue-Router

The advanced

Navigation guard

Navigation indicates that the route is changing. Remember that changes to parameters or queries do not trigger entry/exit navigation guards. You can react to these changes by watching the $Route object respond to changes in the route parameters, or by using the component inside the beforeRouteUpdate.

The guardian of the whole

  • Global front Guard (router.beforeeach)
  • Global Resolution Guard (router.breForeresolve)
  • Global afterhook (router-aftereach) Note: This hook does not have next

Route exclusive guard

You can define beforeEnter guards directly on the route configuration:

const router = new VueRouter({
  routes: [{path: '/foo'.component: Foo,
      beforeEnter: (to, from, next) = > {
        // to -> to jump to the previous routing information
        // from -> The current routing information
        // next() => a function that resolves routing records in the next pipeline}}}])Copy the code

A guard inside a component

Finally, you can define the following route navigation guards directly within the routing component:

  • beforeRouteEnter
  • beforeRouteUpdate(new) 2.2
  • beforeRouteLeave
const Foo = {
  template: `... `,
  beforeRouteEnter (to, from, next) {
    // Called before the rendering component's corresponding route is confirmed
    / / no! Can!!!! Get component instance 'this'
    // Because the component instance was not created before the guard executed
  },
  beforeRouteUpdate (to, from, next) {
    // called when the current route has changed but the component is being reused
    // For example, for a path with dynamic parameters /foo/:id, jump between /foo/1 and /foo/2,
    // Since the same Foo component is rendered, component instances are reused. The hook will be called in that case.
    // Can access component instance 'this'
  },
  beforeRouteLeave (to, from, next) {
    // called when navigating away from the corresponding route of the component
    // Can access component instance 'this'}}Copy the code

BeforeRouteEnter The guard cannot access this because the guard is called before the navigation is confirmed, so the incoming component has not yet been created. However, you can access the component instance by passing a callback to next. The callback is performed when the navigation is confirmed, and the component instance is taken as a parameter to the callback method.

beforeRouteEnter (to, from, next) {
  next(vm= > {
    // After the instance is created, the callback passed by next is called and the instance is passed in as an argument, so the component instance can be accessed through 'vm'})}Copy the code

Note that beforeRouteEnter is the only guard that supports passing a callback to next. For beforeRouteUpdate and beforeRouteLeave, this is already available, so the passing callback is not supported because it is no longer necessary.

beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}
Copy the code

This exit guard is usually used to prevent users from abruptly leaving without saving their changes. This navigation can be cancelled by next(false).

beforeRouteLeave (to, from, next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes! ')
  if (answer) {
    next()
  } else {
    next(false)}}Copy the code

practice

Above talk so much believe you are also muddle. what is the timing of these route calls, and what is the order, below we according to the official explanation to practice

Complete navigation parsing process

  1. Navigation is triggered.
  2. Called in an inactive componentbeforeRouteLeaveThe guards.
  3. Call globalbeforeEachThe guards.
  4. Called in a reused componentbeforeRouteUpdateGuard (+ 2.2).
  5. Called in the routing configurationbeforeEnter.
  6. Resolve the asynchronous routing component.
  7. Called in an activated componentbeforeRouteEnter.
  8. Call globalbeforeResolveGuard (+ 2.5).
  9. Navigation is confirmed.
  10. Call globalafterEachHook.
  11. Triggers a DOM update.
  12. Called with the created instancebeforeRouteEnterGuard passnextCallback function.

router.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/pages/Home'
import {message} from 'ant-design-vue'

Vue.use(VueRouter)

let routes = [
  {
    path: '/'.name: 'Home'.component: Home,
  },
  {
    path: '/index'.name: 'Index'.component: () = > import('.. /pages/Index'),}, {path: '/user/:id'.name: 'User'.props: true.component: () = > import('.. /pages/User'),
    beforeEnter: (to, from, next) = > {
      message.success(Route exclusive guard [beforeEnter] -> FromThe ${from.path} 到 ${to.path}`);
      next()
    }
  }
]

let router = new VueRouter({
  routes
})
router.beforeEach((to, from, next) = > {
  message.success('Global front guard [beforeEach] -> FromThe ${from.path} 到 ${to.path}`.5)
  next();
})

router.beforeResolve((to, from, next) = > {
  message.success('Global resolution guard [beforeResolve] -> fromThe ${from.path} 到 ${to.path}`.5)
  next();
})

router.afterEach((to, from) = >  {
  // The hook has no next and does not change the navigation itself
  message.success(Global afterhook [afterEach] -> fromThe ${from.path} 到 ${to.path}`.5)})export default router
Copy the code

Home.vue

<template> <div class="Home"> <div class="title">Home</div> <a-button type="primary" @click="toIndexHanlder"> to Index </a-button> </div> </template> <script> export default { name: 'Home', beforeRouteLeave(to, from, next) {this.$message. Success (' component inside guard[leave] -> from ${from. next(); }, methods: { toIndexHanlder() { this.$router.push({ path: '/index' }); ,}}}; </script>Copy the code

Index.vue

<template> <div class="Index"> <div class="title">Index</div> <a-button class="my-btn" type="primary" </a-button> <a-button class="my-btn" type="primary" @click="toUserHanlder"> </a-button> </div> </template> <script> export default { name: 'Index', beforeRouteLeave (to, from, next) { console.log(to); next() }, methods: { BackHanlder () { this.$router.go(-1) }, toUserHanlder () { this.$router.push({path: 'user/ck'}) } } } </script>Copy the code

User.vue

<template>
  <div class="User">
    <div class="title">User - {{id}}</div>
    <a-button class="my-btn" type="primary" @click="toUserJump">Forward dynamic routing</a-button>
  </div>
</template>

<script>
export default {
  name: 'User',
  data () {
    return {
      names: ['a'.'b'.'c'.'d'.'e'.'f'].// Random routing
      curNameIndex: 0.lastNameIndex: 0,}},props: ['id'],
  beforeRouteUpdate (to, from, next) {
    this.$message.success('Component inside guard [beforeRouteUpdate] -> fromThe ${from.path} 到 ${to.path}`.5)
    next()
  },
  beforeRouteEnter (to, from, next) {
    // Cannot get this, because the component instance was not created before the guard executed,
    // But in this guard next supports passing callbacks that are called after the instance has been created
    next((vm) = > {
      // vm => Create a Vue instance
      vm.$message.success(Component inside the guard [beforeRouteEnter] -> fromThe ${from.path} 到 ${to.path}`.5)})},methods: {
    // Obtain the method of random route
   getRandomArbitrary (min, max) {
        this.curNameIndex = Math.round(Math.random() * (max - min) + min);
        return this.curNameIndex === this.lastNameIndex 
        ? this.getRandomArbitrary(min, max) 
        : this.curNameIndex;
    },
    toUserJump () {
      this.getRandomArbitrary(0.this.names.length -1)
      this.lastNameIndex = this.curNameIndex;
      this.$router.push({path: `/user/The ${this.names[this.curNameIndex]}`})}}}</script>
Copy the code

demo

The GIF above may be too fast, so take a screenshot of each step and analyze it

The numbers in the upper indices correspond to the order given by the authorities

Route guard triggered by jumping from home.vue to index.vue

    1. Click the button to trigger navigation
    1. Called in the deactivated component guard (home.vue)beforeRouterLeaveTo leave the component
    1. Call the global front guardbeforeEachFrom the route object, we can get the route information before and after the jump
    1. Route resolution is complete

The numbers in the upper indices correspond to the order given by the authorities

Route guard triggered by jumping from index. vue to user/ck

    1. Call the global front guardbeforeEach
    1. Called in the routing configuration (user.vue)befreEnter
    1. Call globalafterEachHook.
    1. Called with the created instancebeforeRouteEnterGuard passnextAnd passes the created instance in

Route guard triggered by jumping from User /ck to User/C

    1. slightly
    1. Because this component is dynamically routed in/user/ck -> user/cThe reuse of the same component is triggeredbeforeRoteUpdate
    1. slightly
    1. slightly

case

The case involves

  • Dynamically modify routing meta information and document title
  • Dynamic routing based transition
  • Intercepting user login status based on navigation guard
  • A 404 page is returned for components that are not defined
  • The exit guard of the route is used to confirm that the user goes to the login page

If you want to go to GitHub, please go to Start👻

Imitation vue-Router source implementation

  • Implement THE SPA page (the page is not refreshed)

    • hash #/beige

    • Hisotry API /beige

  • The corresponding content is displayed according to the URL

    • router-view
    • Data response: the current variable holds the URL address, once changed, dynamically re-execute render corresponding components

Let’s start implementing the Vue-Router plug-in

install

main.js

// Import the vue-router routing table
import router from './my-router'

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

@/vue-router/index.js

// Introduce your own vue-router
import VueRouter from "./my-vue-router";

// Introduce vue-router as a plug-in
Vue.use(VueRouter);

/ / the routing table
letRoutes = [...]const router = new VueRouter({
  routes,
});

export default router;
Copy the code

@/vue-router/my-vue-router

let Vue;
// Vue plug-in format:
// Implement an install method, which will be called during use
myVueRouter.install = function install(_Vue) {
  // _Vue => Vue. Use The constructor passed in
  // Pass in the constructor, which we can modify to extend the prototype

  // this => myVueRouter

  Vue.mixin({
    beforeCreate() {
      // This refers to the component instance
      if (this.$options.router) {
        Vue.prototype.$router = this.$options.router; }}});Vue-router provides two global components
  Vue.component('router-link', Link)
  Vue.component('router-view', View)
}
Copy the code

Here we go. Why do we have to mix it up? The use code is first, the Router instance is created later, and the install logic needs to use the instance. The hook can be mixed with the mixin, and the hook can be mixed with any component instance built by the new Vue. We determine whether the optionsAPi is the root instance by determining whether the router configuration item is passed by the optionsAPi, and then mount the routing configuration item passed by the root instance to the prototype chain for all component instances to share

myVueRouter constructor

constructor(options) {
  // The save option contains the route configuration information
  this.$options = options;

  // Cache the mapping between path and route.
  this.routeMap = {}
  this.$options.routes.forEach(route= > {
    this.routeMap[route.path] = route
  });

  // The current attribute needs to be declared responsive
  // defineReactive is Vue's ability to make the specified data responsive
  Vue.util.defineReactive(
    this."current".window.location.hash.slice(1) | |"/"
  );

  // This in turn does not use Set reason -> the Set method to receive obj must be responsive
  // Vue.set(obj, key, val)


  // 2. Listen for hashChang events and respond when they change
  window.addEventListener("hashchange".() = > {
    // hash: #/about
    console.log(this.current); 
    this.current = window.location.hash.slice(1);
  });
}

Copy the code

We only implement route jumps by listening for hash changes, mainly through the HashChange API

router-view

The next step is to implement the most critical router-view, the route attempt to render the routing component of the corresponding path on the page

Vue.component("router-view", {

  render(h) {
    // Get the router instance to get the path
    // Obtain components from the routing table according to path
    const {routeMap, current} = this.$router
    const component = routeMap[current] ? routeMap[current].component : null;
    
    returnh(component); }});Copy the code

This is a good explanation of why we want to change current to responsive data during initialization. Data responsive: Data changes can be listened to, using these data components will have a dependency on the responsive data in the future if the responsive data changes, the components will be rerendered

router-link

Vue.component("router-link", {
  props: {
    to: {
      type: String.required: true,}},render(h) {
    // h is createElement and returns vNode
    // Get the slot contents
    return h(
      "a",
      {
        attrs: {
          href: "#" + this.to,
        },
      },
      this.$slots.default ); }});Copy the code

Router-link works in a very simple way. It essentially renders a hyperlink, converts to an HREF, and accesses the component’s content through the default slot

Rendering 💗

The source code interpretation

View the official vue-router source address

Vue-router Implementation principle

When the vue-router is instantiated, this. History is initialized. If the mode is passed, the history will be different

constructor (options: RouterOptions = {}) {
    this.mode = mode // Do not pass mode, the default is hash
    
    switch (mode) {
      case 'history':
        this.history = new HTML5History(this, options.base)
        break
      case 'hash': 
        this.history = new HashHistory(this, options.base, this.fallback)
        break
      case 'abstract':
        this.history = new AbstractHistory(this, options.base)
        break
      default:
        if(process.env.NODE_ENV ! = ='production') {
          assert(false.`invalid mode: ${mode}`)}}}// => We'll get an example of this. We'll call some of the push, replace, and go methods on this
Copy the code

Here, taking HashHistory as an example, the push method of Vue-Router is implemented as follows:

push (location: RawLocation, onComplete? :Function, onAbort? :Function) {
    // $flow-disable-line
    if(! onComplete && ! onAbort &&typeof Promise! = ='undefined') {
      return new Promise((resolve, reject) = > {
        this.history.push(location, resolve, reject)
      })
    } else {
      this.history.push(location, onComplete, onAbort)
    }
}
// The push method of this.history is called after the push method is called
Copy the code

HashHistory implements the push method:

function pushHash (path) {
  if (supportsPushState) {
    pushState(getUrl(path))
  } else {
    window.location.hash = path // This is essentially an encapsulation of the window.location.hash method}}Copy the code

Listening on routes is implemented by listening on events corresponding to the hash:

window.addEventListener(
  supportsPushState ? 'popstate' : 'hashchange'.() = > {
    const current = this.current
    if(! ensureSlash()) {return
    }
    this.transitionTo(getHash(), route= > {
      if (supportsScroll) {
        handleScroll(this.router, route, current, true)}if(! supportsPushState) { replaceHash(route.fullPath) } }) } )// We also listen to the popstate and hashChange events provided by the window object to respond to the hash listening
Copy the code

Therefore, the core of Vue-router isto use History to instantiate the corresponding function, and the History is determined by the mode passed in. Different History calls have different underlying methods, but the underlying methods are all instances provided by window.location. For example, hash changes are supported through the hashChange event listener, so vue-Router is essentially a wrapper around native events

In addition, vue-Router provides two components:

Vue.component('RouterView', View)
Vue.component('RouterLink', Link)

      
Copy the code

Write in the last

Since this is a practical article, the whole article will be written in code, and there will be less talk about concepts and basic syntax. If this post helped you, please like 🤓

Practice makes perfect, shortage in one

If there is a piece of writing in the article is not very good or there are questions welcome to point out, I will also keep modifying in the following article. I hope I can grow with you as I progress. Those who like my article can also pay attention to it

I’ll be grateful to the first people to pay attention. At this time, you and I, young, packed lightly; And then, rich you and I, full of it.