VueRouter in 5 minutes (second understanding)

preface

Vue Router is the official route manager of vue.js. Its deep integration with vue.js’ core makes it easy to build single-page applications.

Many students in the interview can only say that the Router internal implementation of hash and history mode, but the internal principle is not known. This article uses a handwritten Hash mode version of the VueRouter to quickly break down the internal mechanism of the Router.

1. Use retrospectives

Before we begin, let’s do a quick review of the use of the VueRouter

1. Installation: Vue add Router

2.router.js

Import router from 'vue-router' vue. use(router) to create a router instance and export const routes=[{...}] export default new Router({routes})Copy the code

3. Main. Js

New Vue({router,}).$mount("#app");Copy the code

4. Step 4: Add routing view and corresponding code in app. vue

<router-view></router-view>
<router-link to="/">Home</router-link> <router-link to="/other">other</router-link>
this.$router.push('/')
this.$router.push('/other')
Copy the code

Problem 2.

After reviewing the use of the Router, we begin the body. But before we do that, here are a few things to think about.

2.1 What problems are we trying to solve with VueRouter?

A: In a single page application, when the URL address changes, the page cannot be refreshed, but the content corresponding to the URL address is displayed

2.2 According to the above requirements, what is the realization method and how to split tasks?

A:

  • Url address changed, page not refreshed: hash\history Api
  • Display the corresponding content according to the URL address: listen on the route, get the current address, find the corresponding Componet from the configuration item of the user, and render in router-view

2.3 We are going to implement a VueRouter. What exactly do we have to do?

A:

The first step is definitely to implement a VueRouter class, with four things to do inside the class.

  • Saves the configuration options of the user when generating the Router instance.
  • Listen for the current hash address and process that address into responsive data
  • Implement the install method of the plug-in

    VueRouter is a plug-in that is registered with vuue.use (), which calls the install method and passes the Vue instance to the install method as an argument. So our first step is to implement the install method of a plug-in. Inside the method is some concrete implementation that we want to implement at mount time.

    • Mount the Router instance

    • Register two router-links and router-Views

      Routerlink is essentially rendered as an A tag, and Router-View is used to find and render corresponding Componet components from user-defined routing options based on the current hash

3. Code implementation

Well, after answering the above questions, we started to hand polish a simple version of vue-Router, and you can also see the actual implementation from the VueRouter source code.

3.1 Implement a VueRouter class

  • Save the configuration items in Constructor
  • Initialization and reactive processing of the current path (hash) for subsequent router-view components to find routing components
Class vueRouter {constructor(options) {constructor(options) {this.$options = options; / / need to statement in response to the current attribute type. / / the Vue util. DefineReactive is to provide methods of reactive Vue Vue. Util. DefineReactive (this, "current", window.location.hash.slice(1) || "/" ); // 2. Listen for hashchang events and respond window.addEventListener("hashchange", () => {// hash: #/about this.current = window.location.hash.slice(1); }); }}Copy the code

3.2 Implement the vueRouter class install method, this method will be executed when vue.use, contains two functions,

  • Mount the instance Router
Let Vue vueRouter. Install =function(_vue){Vue=_vue; The router instance was not generated (see initial use review), so by declaring vue. mixin in use, the router will only be mounted when Vue is instantiated, i.e. New Vue({router,render:) in mian.js. h => h(App)}).$mount('#app') Vue.mixin({ beforeCreate(){ if(this.option.router) Vue.prototype.$router=this.option.router }})}Copy the code
  • Register router-link and router-view global components
let Vue vueRouter.install=function(_vue){ Vue=_vue Vue.mixin({ beforeCreate(){ if(this.option.router) Prototype.$router=this.option.router}}) {vue.prototype.$router=this.option.router}}) {vue.prototype.$router=this.option.router}} <router-link to="/about"></router-link> props: {to: {type: String, required: Render (h) {// h is createElement, Return vnode / / < the router - link to = "/ about" > < / router - the link > / / < a href = "# / about" > < / a > / / return < a href = {' # '+ This. To}>{this.$slot.default}</a> return h("a", {attrs: {href: "#" + this.to, }, }, this.$slots.default ); }}); Vue.component("router-view", {render(h) {// render(h) { // If the reactive data changes in the future, these components will re-render let Component = null; {this.$router = {this.$router = {this.$router = {this.$router = {this.$router = {this.$router = {this.$router = {this.$router = {this. The current is reactive, drawn from window.location.hash, and as soon as the current changes, the component will be rerendered, Const route = this.$router.$options.routes.find((route) => route.path === this. if (route) { component = route.component; } // 1. Get the hash part, get path // 2. }}); }; }Copy the code

At this point, we have implemented a Vue responsive processing that matches different hash values to different components and renders a simple route in the routerView component. Of course, the real source code to consider the situation is much more complex than the present situation, the follow-up will fill up the nested routine by the analysis and concrete implementation.

4. Complete code

vue-router.js

let Vue; // Vue plugin form: Class vueRouter {constructor(options) {// This.$options = options; / / to the current property declaration for the response of Vue. Util. DefineReactive (this, "current", the window. The location. The hash. Slice (1) | | "/"); // 2. And changes in response to a window. The addEventListener (" hashchange ", () = > {. This current = window. The location. The hash. Slice (1); }); VueRouter. Install = function(_Vue) {// Pass in the constructor, we can modify its prototype to extend it. // This is KVueRouter // 1. Register $router // Delay execution of the following code until router instance is created // global mix: Vue. Mixn Vue. Mixin ({beforeCreate() {this.$options.router) {Vue. Prototype this.$options.router; }}}); Vue.component("router-link", {props: {to: {type: String, required: // 2. True,},}, render(h) {// h is createElement, Return vnode / / access slot content / / < the router - link to = "/ about" > < / router - the link > / / < a href = "# / ohter" > < / a > / / return < a href = {' # '+ this.to}>{this.$slots.default}</a> return h( "a", { attrs: { href: "#" + this.to, }, }, this.$slots.default ); }}); Vue.component("router-view", {render(h) {// Data responsiveness: data changes can be heard, using these data components will have dependencies on the responsive data // if the responsive data changes in the future, these components will re-render // 0. Log (this.$router.$options, this.$router. let component = null; const route = this.$router.$options.routes.find( (route) => route.path === this.$router.current ); if (route) { component = route.component; } // 1. Get the hash part, get path // 2. }}); }; export default VueRouter;Copy the code