This article will show you how to manually implement a mini version of the Vue-Router, which we call in this articleKRouter)

What our KRouter will do:

  • Normal route jump

Demand analysis

We need to consider two things:

  • The SPA page application cannot be refreshed, so we came up with two modes. (Hash is used in this article, and History is used when writing vuex.)

    • Hash mode (eg:#/aboutAnd the event:onchange)
    • History API mode (eg:/aboutAnd the event:pushState)

    Since this is a single-page application, we can only use hash and history to implement our requirements, and both have corresponding events.

  • The corresponding content is displayed according to the URL

    • router-view
    • The data response: current variable holds the URL address and dynamically reperforms the rendering once it changes

    A router-view is a component container that defines the current url, and then retries the corresponding Component from the routing table based on current. Another thing to consider is that if current changes, the component displayed in our corresponding Router-View will also change accordingly.

Code implementation

Our goal for writing code is:

  • Implement KRouter class
  • Implement the install method

1. Environment construction

  • Create a project

    vue create myapp
    npm run serve
    Copy the code
  • New SRC/KRouter/index. Js

  • Modify SRC /router/index.js to refer to our own KRouter;

    import VueRouter from "vue-router";
    / / changed to
    import VueRouter from ".. /KRouter/index";
    Copy the code

At this point our browser looks at our project run error. This is not surprising since our KRouter/index.js file is empty, with no exports. Let’s see how to do that!

2. Realize the shell of KRouter

  • In the SRC /KRouter/index.js file

    class KRouter {}
    
    KRouter.install = function () {};
    
    export default KRouter;
    Copy the code
  • Look at the browser and see if it’s a milestone. At this time of the error to solve is not simple?

  • Example Modify the SRC /KRouter/index.js file

    Use (Plugin); install (Vue); use(Plugin); install (Vue); So we just use the Vue.component global API to register the router-link and router-view global components.

    class KRouter {}
    
    KRouter.install = function (_Vue) {
      _Vue.component("router-link", {
        render(h) {
          return h("a"."Hyperlink"); }}); _Vue.component("router-view", {
        render(h) {
          return h("div"."Component Container"); }}); };export default KRouter;
    
    Copy the code
  • Now look at the browser, is it perfect, very simple, no mistakes.

3. Implement KRouter class

The second step before the first simple implementation of the install method, just to not report errors, is not perfect. Let’s implement the KRouter class first.

First, let’s think about how we normally use vue-router, usually this.$router.xxx, and then configure a routing table, instantiate it, and mount it to the vue instance. The diagram below:

As you can see from the diagram, routes will be passed to the constructor, and then we need a variable (which we define as current) to store our current URL. And we’re going to follow that thought step by step. So the code looks like this:

class KRouter {
  constructor(options) {
    this.$options = options;
    this.current = "/";
  }
}

KRouter.install = function (_Vue) {
  _Vue.component("router-link", {
    render(h) {
      return h("a"."Hyperlink"); }}); _Vue.component("router-view", {
    render(h) {
      return h("div"."Component Container"); }}); };export default KRouter;
Copy the code

4. Mount the KRouter to the Vue prototype

This.$options is a common instance API to get the parameters passed to the component instance. You can output the parameters by yourself.

Portal: vue. mixin and this.$options

class KRouter {... } KRouter.install =function (_Vue) {
  _Vue.mixin({
    beforeCreate() {
      if (this.$options.router) {
        _Vue.prototype.$router = this.$options.router; }}}); . };export default KRouter;

Copy the code

Now this.$options.router is the root component, because we only passed the router in the root component, as shown in the figure below:

What, you still don’t believe me?

So let’s change the code and test it

class KRouter {... } KRouter.install =function (_Vue) {
  _Vue.mixin({
    beforeCreate() {
      console.log(this.$options.router); }}); . };export default KRouter;
Copy the code

Take a look at the browser output and see if there is only one component that has this.$options.router. Learn to waste

5. Improve the router-View component

class KRouter {... } KRouter.install =function (_Vue) {... _Vue.component("router-view", {
    render(h) {
      const current = this.$router.current;
      const component = this.$router.$options.routes.find(
        (v) = > v.path == current
      ).component;
      returnh(component); }}); };export default KRouter;

Copy the code

In the previous step _vue.mixin, the KRouter instance has been mounted on vue.prototype, which is $router.

This.$router is used to retrieve the current url, which is our variable, current, and find the item that matches the path === current in routes.

Finally, rendering is done through h function, which is the core principle of router.

6, the most important step, responsive processing.

Now our KRouter can render components, but since it is a route, it can’t jump. So the next thing we’re going to implement is a route jump.

Example Modify the router-link component

The router-link component is normally used as follows:

</router-link>Copy the code

So we modified our router-link code

KRouter.install = function (_Vue) {
  _Vue.component("router-link", {
    props: {
      to: {
        type: String.required: true,}},render(h) {
      return h("a", { attrs: { href: ` #The ${this.to}`}},this.$slots.default); }}); };export default KRouter;
Copy the code

The KRouter listens for hashChange events

class KRouter {
  constructor(options) {
    this.$options = options;
    this.current = "/";
    window.addEventListener("hashchange".() = > {
      this.current = window.location.hash.slice(1);
    });
  }
}
KRouter.install = function(){... }export default KRouter;

Copy the code

Reactive processing of current

At this point, you realize that, having done everything, when you click on the route, the router-view still doesn’t render the component. Right, that’s because your current is not responsive, and the next thing we’re going to do is make current responsive.

Vue provides us with a method defineReactive. DefineReactive (obj,key,value)

class KRouter {
  constructor(options) {
    this.$options = options;

    Vue.util.defineReactive(this."current"."/");// Add a current property to the instance. The default value is "/"
    window.addEventListener("hashchange".() = > {
      this.current = window.location.hash.slice(1); }); }}export default KRouter;

Copy the code

People say, hey, where did you get your Vue from? Can you just import Vue from “Vue”?

The answer is: of course

But do you want to NPM install vue when you are developing a plugin? It’s obviously a waste of resources.

So adjust your thinking, and then post a full copy of the code as follows:

let Vue;
class KRouter {
  constructor(options) {
    this.$options = options;

    Vue.util.defineReactive(this."current"."/");
    window.addEventListener("hashchange".() = > {
      this.current = window.location.hash.slice(1);
    });
  }
}

KRouter.install = function (_Vue) {
  Vue = _Vue;
  _Vue.mixin({
    beforeCreate() {
      if (this.$options.router) {
        _Vue.prototype.$router = this.$options.router; }}}); _Vue.component("router-link", {
    props: {
      to: {
        type: String.required: true,}},render(h) {
      return h("a", { attrs: { href: ` #The ${this.to}`}},this.$slots.default); }}); _Vue.component("router-view", {
    render(h) {
      const current = this.$router.current;
      const component = this.$router.$options.routes.find(
        (v) = > v.path == current
      ).component;
      returnh(component); }}); };export default KRouter;

Copy the code

So if you think about this.$router-push API, how do you do that? Do you already have an idea!

conclusion

To nuggets to write an article, the original intention is to make a note, to prevent the back of their own will forget. As programmers know, after a period of time do not touch, will be rusty. Simply write a bit more detailed, with everyone to communicate. May we support each other on the path of procedure and stay true to our original aspiration.

The layout is a little low, don’t mind, hahaha.