Why do YOU need front-end routing

With the separation of the front and back ends, most apps are now presented in a SPA (Single Page Application) format. Why do you choose SPA? Here’s why:

  • All user operations are performed on the same page. Good user experience.
  • In contrast to multiple pages, a single page doesn’t need to make multiple requests to the server to load the page (just request an.html file once), just request data from the server (thanks to Ajax). Therefore, the browser does not need to render the entire page. Good user experience.

At the end of the day, it’s because SPAs provide a better user experience.

In order to better implement SPA, front-end routing is essential. Consider a scenario where a user hits the forced refresh button in some state on a SPA page. If there is no front-end route to remember the current state, the user clicks the button and is returned to the original page state. That’s not what users want.

Of course, the need for front-end routing is another point: we can better manage the SPA page. By pairing components with routes, it can provide a reference for the division and management of components within SPA according to the hierarchy of routes.

Hash routing mode and History routing mode

These are two common front-end routing patterns.

Hash routing mode

Hash mode uses the # XXX part of the browser URL suffix to implement front-end routing. By default, the # XXX hash part of the URL suffix is used to function as an anchor point for the web page, and the front-end routing now sees this point and takes advantage of it.

For example, the URL: http://www.abc.com/#/hello has a hash value of #/hello.

Why look at the hash part of the browser URL suffix? The reason is simple:

  • The hash in the suffix of the browser URL has changed so that the request is not triggered and the server is not affected at all. Its changes do not reload the browser page.
  • More importantly, the state of the page is linked to the url of the browser because the url of the hash is logged by the browser, so you can see that the browser is working backwards and forwards.

The principle behind hash mode is the onHashChange event, which can be listened for on the Window object.

History Routing Mode

With the advent of the HISTORY API in HTML5, front-end routing is starting to evolve. Hashchange only changes code snippets following #, while the history API (pushState, replaceState, Go, back, Forward) gives the front end complete freedom. In short, it’s more powerful: split into two parts, switch and modify.

Routing switch

Refer to MDN to switch historical status, including back, Forward, and Go, corresponding to the forward, backward, and forward operations of the browser.

history.go(2 -);// Back up twice
history.go(2);// Proceed twice
history.back(); / / back
hsitory.forward(); / / to go forward
Copy the code

Routing changes

PushState and replaceState are two methods to change the historical state:

/** ** Parameter Meaning ** state: Indicates the data that needs to be saved. When the popState event is triggered, the ** title: title can be obtained in the event	
window.history.pushState(state, title, url) 

// Assume the current URL is: https://www.abc.com/a/
1 / / examples
history.pushState(null.null.'./cc/') / / url for https://www.abc.com/a/cc/ at this time
2 / / examples
history.pushState(null.null.'/bb/') // The url is https://www.abc.com/bb/
Copy the code

Similarly, history mode can listen for corresponding events:

window.addEventListener("popstate".function() {
    // Listen for browser forward and backward events. PushState and replaceState methods do not trigger
});
Copy the code

Note the History mode

The History mode has more options than the Hash mode. But it comes with some caveats of its own: The History mode sends a request to the server when the user clicks force refresh.

To solve this problem, the server needs to do the corresponding processing. The server can handle different urls, or it can simply return the same index.html page for any unmatched URL request.

What does the Vue Router do?

As a very important member of Vue ecosystem, Vue Router implements routing management of Vue applications. It can be said that Vue Router is a route manager tailor-made for Vue, with many function points. Its internal implementation is strongly coupled to the Vue itself (the Vue Router internally utilizes Vue’s data responsiveness).

Let’s look at a typical Vue Router configuration:

import Vue from "vue";
import App from "./vue/App.vue";
import VueRouter  from 'vue-router';

// As a plug-in, use VueRouter
Vue.use(VueRouter);

// Route configuration information, which can be imported from external files, is written here for demonstration purposes
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const routes = [
  { path: '/'.component: Foo },
  { path: '/bar'.component: Bar }
]

// Initializes and associates with Vue instances
const router = new VueRouter({routes});
new Vue({
  router,
  render: h= > h(App),
}).$mount("#root");
Copy the code

As you can see, the VueRouter was introduced into the Vue system as a plug-in. Embedding specific router information into each Vue instance is passed in as a constructor argument to the Vue.

In the meantime, see how to use it:

//routerExample.vue
<template>
    <div>
        <h1 @click="goBack">App Test</h1>
        <router-link to="/">foo</router-link>
        <router-link to="/bar">bar</router-link>

        <router-view></router-view>
    </div>
</template>

<script>
export default {
  methods: {
    goBack() {
      console.log(this.$router);  
      window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/')
    }
  }
}
</script>

<style lang="less" scoped>

</style>
Copy the code

In the above code, we can use router-link and router-View components directly. They were introduced with the Vue Router and are used as global components.

This is the simplest way to use a Vue Router. Let’s take a look at how to implement the above simple function, make your own Vue Router.

A simple Vue Router implementation

Given the above process, the simplest Vue Router should include the following implementation steps:

  • Implement the writing method of the plug-in specified by Vue, and introduce our own Vue Router into the Vue system as a plug-in.
    • Router function 1: Parses the routes option passed in for invocation
    • Router function 2: Monitors URL changes (using history and hash routing methods)
  • Implement two global components:router-linkandrouter-view

Take a look at the implementation of the custom Vue Router:

//FVueRouter.js

 let Vue; // Save a reference to the Vue constructor, which is deeply bound to Vue

 class FVueRouter {
    constructor(options){
        this.$options = options;
      	// Save the mapping between route paths and routing components
        this.routerMap = {};

        // The current URL must be responsive, using a new Vue instance to implement responsive functionality
        this.app = new Vue({
            data: {current : "/"}
        })
    }

    init(){
        // Listen for routing events
        this.bindEvents();
        // Parse the routes passed in
        this.createRouterMap();
        // Global component declaration
        this.initComponent();
    }

    bindEvents(){
        window.addEventListener('hashchange'.this.onHashChange.bind(this));
    }

    onHashChange(){
        this.app.current = window.location.hash.slice(1) | |'/';
    }

    createRouterMap(){
        this.$options.routes.forEach(route= > {
            this.routerMap[route.path] = route;
        })
    }

    initComponent() {
        / / form: < the router - link to = "/" > transformation target = > < a href = "# /" > XXX < / a >
        Vue.component("router-link", {
          props: {
            to: String,
          },
          render(h) {
            // h(tag, data, children)
            return h('a', {
                attrs: {href: The '#' + this.to}
            }, [this.$slots.default])
          },
        });
        // Get the path Component and render it
        Vue.component("router-view", {
            render: (h) = > {
                // This points correctly inside FVouter because of the arrow function
                const Component = this.routerMap[this.app.current].component;
                return h(Component)
            }
        })
      }
 }

 // All plug-ins need to implement the install method, which is passed in as a Vue constructor
 FVueRouter.install = function(_Vue){
    // Save the Vue constructor
    Vue = _Vue;

    // To implement a mixin operation, the install phase of the plug-in is very early and there is no Vue instance at this point
    // Therefore, with mixins, the corresponding operations are deferred to the Vue instance construction process.
    Vue.mixin({
        beforeCreate(){
            // Get an instance of the Router and mount it on the prototype
            if(this.$options.router){
                // The root component beforeCreate is executed only once
                Vue.prototype.$router = this.$options.router;

                this.init(); }}})}export default FVueRouter;
Copy the code

Here is the simplest implementation. There are a few points worth noting:

  • The above code sets up a basic Vue Router code shelf and is ready to run. But details still need to be considered.
  • About plug-in writing: A custom plug-in must implement an install method inside, passing in the Vue constructor as an argument.
  • A new Vue instance is used to make the URL hash variable data responsive.
  • Arguments to the render functionh, which is actually the createElement function. The specific usage is worth investigating. The code uses the simplest processing.

At the end

In this article, we explained two common modes of front-end routing: Hash mode and History mode. At the same time, we tried to implement a simple Vue Router by ourselves. For more details on the Vue Router, see the Vue Router website. Hope you found this article useful.


Vue source code interpretation

(1) : Vue constructor and initialization process

(II) : Data response and implementation

(3) : array responsive processing

(iv) Vue’s asynchronous update queue

(5) The introduction of virtual DOM

(VI) Data update algorithm — Patch algorithm

(7) : realization of componentization mechanism

(8) : computing properties and listening properties

The Optimize stage of the compilation process

Vue

Vue’s error handling mechanism

Parse the working process of Vue in handwritten code

Vue Router handwriting implementation