preface

In the world of technology, there are no miracles, only wonderful, amazing use of technology. —- southern small dishes to see a word, front-end revolutionary events: Ajax to achieve active request local refresh, control of routing control; The former is easy to understand, while the latter is more surprising. The solid state thinking of my previous development projects:

  1. The back-end server defines two types of interfaces: page jump and data return;
  2. The front end obtains data and renders the page, and pays attention to the interface and user experience;
  3. Plus some database encryption to avoid HTTP statelessness and use sessions and so on blablabla’s little points. But front-end routing came out of nowhere, and all of a sudden, the small and silly smug bombing of my back end was gone. The popularity of a new thing is bound to lie in the problems it solves. Front-end routing points out the three traditional problems:
  • The screen is blank and the page is slowly refreshed
  • In some cases, with Ajax requests, you can keep the page from being refreshed, so the page changes but the Url doesn’t change, and the user can’t copy to the desired address
  • Increase server pressure, code redundancy. Thus a full stack project becomes an implementation like this:
  1. The back-end server defines the data return API;
  2. The front end constructs the SPA application, invokes the interface and performs bidirectional data binding rendering based on MVVM
  3. The front-end route is updated without refreshing content

As the front-end route deep as the sea, no progress bar from now on

Train of thought to realize

First of all, don’t talk about how to achieve, think first

What are the requirements: No front-end refresh updates the contents of mounted nodes
What is the change point: location

Each change corresponds to the contents of a mount point (naturally, we need a routing table that is the k-V of the path and the contents of the mount point, which can be implemented via JSON)

Find the right hook function: (mostly hashchange/popstate today)

The technical implementation

In traditional back-end routes, the page is refreshed each time a new request is sent. This causes poor experience, such as a blank screen and time consuming. Therefore, front-end routes are loaded immediately. They do not request the server, but load the corresponding components of routes. The implementation of this idea mainly adopts two schemes: Hashchange and history

  • hash
    1. Retrieves the hash value of the address using window.location.hash, based on the hashchange event
    2. The mapping between hash and component content is set by constructing the Router class and the routes object
  • history
    1. Using THE MVVM of VUE, the router-view to be rendered is set through the current of data in VUE, so as to achieve dynamic SPA

history

html

<div>
        <a href="javascript:;" data-href="/">home</a>
        <a href="javascript:;" data-href="/book">book</a>
        <a href="javascript:;" data-href="/movie">movie</a>
        <div id="content"></div>
    </div>
Copy the code

js

Router {constructor(opts) {this.routes = {}, this.init(); this.bindEvent(); opts.forEach(item => { this.route(item.path, () => { document.getElementById('content').innerHTML = item.component; })})}init{// Render route window.adDeventListener () {// render route window.adDeventListener ('load', this.updateView.bind(this)); // When the active history entry changes, the popState event is emitted. // If the active history entry was created by a call to history.pushState (), // or is affected by a call to history.replacestate (), // The state property of the popState event contains a copy of the state object for the history entry. window.addEventListener('popstate', this.updateView.bind(this)); } // Route renderupdateView() {
        const currentUrl = window.location.pathname || '/'; this.routes[currentUrl] && this.routes[currentUrl](); } route(path, fn) {this.routes[path] = fn; } push(url){ window.history.pushState({},null,url); This.updateview ()} // Bind events to hyperlinksbindEvent() {
        const _this = this;
        const links = document.getElementsByTagName('a');
        [].forEach.call(links, link => {
            link.addEventListener('click'.function () {
                const url = this.getAttribute('data-href'); console.log(url); _this.push(url); // Instantiate router const router = new router ([{path:'/',
            component: 'home'
        }, {
            path: '/movie',
            component: 'movie'
        }, {
            path: '/book',
            component: 'book'
        }])

Copy the code

hash

Hash also has the following features:

The hash value in the URL is just a state on the client side, meaning that the hash part is not sent when the request is made to the server side. Changes to the hash value add a record to the browser’s access history. So we can switch the hash using the browser’s back and forward buttons. We can use the HashChange event to listen for changes to the hash.

There are also two ways to change the hSAH. One is to use the A tag and set the href attribute. When the user clicks the tag, the URL will change and the hashchange event will be triggered

<! DOCTYPE html> <html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <a href="# /" data-href="/">home</a>
    <a href="#/book" data-href="/">book</a>
    <a href="#/movie" data-href="/">movie</a>
    <div id="content">

    </div>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
    <script>
        // window.onload = function (params) {
        //     window.location.href += '# /' 
        // }

        const Home = {
            template: '<div>home</div>'
        }
        const Book = {
            template: '<div>book</div>'
        }
        const Movie = {
            template: '<div>movie</div>'
        }
        class Router {
            constructor(opts) {
                // this.path = opts.path;
                // this.component = opts.component;
                // this.routes = opts.routes;
                this.routes = {

                }
                // console.log(opts);
                
                opts.forEach(item => {
                    this.route(item.path,()=>{
                        document.getElementById('content').innerHTML = item.component;
                    })
                })
                console.log(this.routes);
                
                this.init()
            }
            bindEvent() {}init() {
                window.addEventListener('load',this.updateView.bind(this))
                window.addEventListener('hashchange', this.updateView.bind(this))

            }
            updateView(e) {
                // console.log(e,'updated');
                // console.log(e.newURL.indexOf(e.oldURL));

                // console.log(e.newURL.substring(e.newURL.indexOf(e.oldURL)));
                const hashTag = window.location.hash.slice(1) || '/'
                console.log(window.location.hash.slice(1));
                this.routes[hashTag] && this.routes[hashTag]()

            }
            route(path,cb){
                this.routes[path] = cb;
            }
        }
        new Router([
            {
                path: '/',
                component: 'home',
            },
            {
                path: '/book',
                component: 'book'
            },
            {
                path: '/movie',
                component: 'movie'
            }
        ])
    </script>
</body>

</html>
Copy the code