preface

From the previous section, we learned that there are two implementations of the front end reason, Hash routing and History routing, and used each to implement a front end route.

Let’s combine Vue with Hash routing to implement a very simple Vue-router.

Begin to implement

Imagine implementing a Vue-Router. How would you use it? Refer to the official vue-Router usage to see how HTML is used:

<div id="app">
  <p>
    <router-link to="# /">home</router-link>
    <router-link to="#/book">book</router-link>
    <router-link to="#/movie">movie</router-link>
  </p>
  <router-view></router-view>
</div>
Copy the code

There are two components that we need to implement: router-link and router-view. Let’s look at js again:

const Home = { template: '<div>home</div>' };
const Book = { template: '<div>book</div>' };
const Movie = { template: '<div>movie</div>' };

const routes = [
  { path: '/'.component: Home },
  { path: '/book'.component: Book },
  { path: '/movie'.component: Movie }
];

const router = new VueRouter(Vue, {
  routes
});

new Vue({
  el: '#app'
});
Copy the code

There will be our own defined components Home, Book, and Movie, with their respective routes. Our VueRouter implementation is different from the official VueRouter. When VueRouter is new, we pass Vue as an argument instead of injecting it to the root instance.

And then there’s the VueRouter implementation.

VueRouter

How to implement VueRouter

  1. The bindinghashchangeEvent to realize front-end routing;
  2. Make a route mapping between the incoming routes and components, and switch which route to find the corresponding component.
  3. You need a new Vue instance and you do responsive communication, when the route changes,router-viewResponds to updates;
  4. registeredrouter-linkrouter-viewComponents.

So let’s create a VueRouter:

class VueRouter {
  constructor (Vue, options) {
    this.$options = options; }}Copy the code

The binding event

Add a method to the VueRouter that binds to an event and fires the onHashChange method if the route changes.

constructor (Vue, options) {
  this.init();
}

// Bind the event
init () {
  window.addEventListener('load'.this.onHashChange.bind(this), false);
  window.addEventListener('hashchange'.this.onHashChange.bind(this), false);
}
Copy the code

Route mapping table

Set the incoming options as a route mapping table so that you can find the corresponding component through the route.

constructor (Vue, options) {
  this.$options = options;
  this.routeMap = {};
  this.createRouteMap(this.$options);
}

// Route mapping table
createRouteMap (options) {
  options.routes.forEach(item= > {
    this.routeMap[item.path] = item.component;
  });
}
Copy the code

Options, the relationship between routing and components:

const routes = [
  { path: '/'.component: Home },
  { path: '/book'.component: Book },
  { path: '/movie'.component: Movie }
];
Copy the code

Generated routing mapping table:

this.routeMap = {
  '/': Home,
  '/book': Book,
  '/movie': Movie
};
Copy the code

The response

We need to create a new Vue instance and store the current route in its data. When current is changed, the router-view will update the view itself.

constructor (Vue, options) {
  this.app = new Vue({
    data: {
      current: '# /'}}); }// Get the current hash string
getHash () {
  return window.location.hash.slice(1) | |'/';
}


// Set the current path
onHashChange () {
  this.app.current = this.getHash();
}
Copy the code

If you use this.app.current in the router-view, it will be updated as soon as it is updated.

Certified components

Router-link is actually a tag that can be clicked to trigger a HashChange. Router-view implements a render method that takes the component of the current route and renders it.

constructor (Vue, options) {
  this.initComponent(Vue);
}

// Register the component
initComponent (Vue) {
  Vue.component('router-link', {
    props: {
      to: String
    },
    template: '<a :href="to"><slot></slot></a>'
  });

  const _this = this;
  Vue.component('router-view', {
    render (h) {
      var component = _this.routeMap[_this.app.current];
      returnh(component); }}); }Copy the code

The complete code

So, a simple vue-router is created. The entire code looks like this:

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

  // Bind the event
  init () {
    window.addEventListener('load'.this.onHashChange.bind(this), false);
    window.addEventListener('hashchange'.this.onHashChange.bind(this), false);
  }

  // Route mapping table
  createRouteMap (options) {
    options.routes.forEach(item= > {
      this.routeMap[item.path] = item.component;
    });
  }

  // Register the component
  initComponent (Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      template: '<a :href="to"><slot></slot></a>'
    });

    const _this = this;
    Vue.component('router-view', {
      render (h) {
        var component = _this.routeMap[_this.app.current];
        returnh(component); }}); }// Get the current hash string
  getHash () {
    return window.location.hash.slice(1) | |'/';
  }

  // Set the current path
  onHashChange () {
    this.app.current = this.getHash(); }}Copy the code

The last

Combining Vue with Hash routing, listening for hashChange events, and using Vue’s response mechanisms and components, you have a Vue-router implemented above.

All source reference here.