Talking about front-end routing

What is Frontend Routing

For users, routing is the correspondence between the URL in the browser's address bar and the web page they see. For web developers, routing is more like the correspondence between urls and processing functions.

In traditional server-side routing, different web pages are returned according to different URLs requested by the client. In this case, the pressure on the server will increase, and the request will be repeated every time, resulting in a slow response and a degraded user experience. Thus, single page application (spa, single page application) came into being. In the process of changing the url address, the switch between different UIs is realized through js (the operation of js on the DOM), instead of re-requesting the page from the server, and only requesting data from the server through ajax. For users, this kind of No refresh, instant response is a better experience. Among them, different UIs are displayed according to the changes of the url address bar, which is realized through front-end routing. The current mainstream front-end frameworks that support single-page applications basically have matching or third-party routing systems.

Implementation of front-end routing

Before the HTML5 history API appeared, front-end routing was mainly implemented through hash, which was compatible with lower-version browsers. The two methods are described below.

  • Method 1: Based on hash (location.hash+hashchange event)

We know that the value of location.hash is #the content behind the url. In http://www.163.com#neteasethis URL, location.hash='#netease'. The hash satisfies the following characteristics, so that it can realize front-end routing:

  1. The change of the hash value in the url will not reload the page, because the hash is used to guide the behavior of the browser and is useless to the server, so it will not be included in the http request.
  2. The change of the hash value will add a record to the browser's access history, that is, the hash switching can be controlled through the browser's back and forward buttons.
  3. We can monitor the change of the hash value through the hashchange event, so as to respond to the logical processing of different paths.
window.addEventListener("hashchange", funcRef, false)

In this way, we can update the corresponding view according to the hash value in the hashchange event, but will not re-request the page. At the same time, an access record is added to the history, and the user can still pass the forward and back keys. Implement UI switching.

There are 2 ways to trigger the change of the hash value:

One is to set the href attribute through the a tag. When the tag is clicked, the address bar will change, and the hashchange event will be triggered at the same time.

<a href="#kaola">to KAOLA</a>

The other is to directly assign the value to location.hash through js, which will also change the url and trigger the hashchange event.

location.hash="#kaola"

The following shows a simple router implemented by hash:

function Router() {
    this.routes = {};
    this.currentUrl = '';
}
Router.prototype.route = function(path, callback) {
    this.routes[path] = callback || function(){};
};
Router.prototype.refresh = function() {
    this.currentUrl = location.hash.slice(1) || '/';
    this.routes[this.currentUrl]();
};
Router.prototype.init = function() {
    window.addEventListener('load', this.refresh.bind(this), false);
    window.addEventListener('hashchange', this.refresh.bind(this), false);
}
window.Router = new Router();
window.Router.init();
// 添加路由规则
Router.route('/', function() {
    // 设置响应内容
});
Router.route('/blue', function() {
    // 设置响应内容
});

【route vs routes】

A route is a route, which associates a URL path with a processing function, and is a mapping rule between url and function. For example, in the above code, a routing rule can be set through the route on the prototype to associate a path with its callback.

The router is more like a container, or a mechanism, which manages a set of routes. Simply put, route just maps URLs and functions, and after receiving a URL, it goes to the routing mapping table to find the corresponding function. This process is handled by the router. As in the above code, the router manages the incoming route, and when the hash changes, it responds to its corresponding function according to the current url.

  • Method 2: Based on the new API of History (history.pushState()+popState event)

The new API on the history object in HTML5 can also implement front-end routing. The address of the url can be modified by the pushState() method or the replaceState() method, and the change of the address can be monitored in the popstate event. The difference is that the manual pushState() will not trigger the popstate event.

Let’s first understand the next two new APIs: history.pushState and history.replaceState, both of which receive three parameters:

window.history.pushState(null, null, "http://www.163.com");
  • state object, a JavaScript object associated with new history entries created with the pushState() method. Whenever the user navigates to the newly created state, the popstate event is fired and the object can be used in the event.
  • title: Pass in a short title for the current state. Now most browsers do not support or ignore this parameter, it is better to pass in null instead;
  • Address (URL): The address of the new history entry. The browser will not load the address after the pushState() method is called, but it may try to load it later, for example if the user restarts the browser. The new URL does not have to be an absolute path; if it is a relative path, it will be based on the current URL; the incoming URL and the current URL should be of the same origin , otherwise, pushState() will throw an exception. This parameter is optional; if not specified, it is the current URL of the document.

The two APIs are similar in that they both operate on the browser's history without causing a page refresh. The difference is that pushState adds a new history, while replaceState replaces the current history. These two APIs, plus the popstate event triggered by state changes, provide another way of routing a single page should.

The following shows a simple demo using this approach:

<p id="menu">
 <a href="/profile" title="profile">profile</a>
 <a href="/account" title="account">account</a>?
</p>
<div class="main" id="main"></div>
<script>
;(function(){
    var menubox = document.getElementById('menu');
    var mainbox = document.getElementById('main');
    
    menubox.addEventListener('click',function(e){
        e.preventDefault();
        var elm = e.target;
        var uri = elm.href;
        var tlt = elm.title;
        history.pushState({path:uri,title:tlt},null,uri);
        mainbox.innerHTML = 'current page is '+tlt;
    })
    window.addEventListener('popstate',function(e){
        var state = e.state;
        console.log(state);
        mainbox.innerHTML = 'current page is '+state.title; // 还原UI
    })
})()
</script>

When we switch in the history, the popstate event is triggered, and the UI corresponding to the current state can be restored in the event. As for the way to trigger popstate event, each browser implements it differently, we can do compatible processing according to different browsers.

Comparing the two methods, Hash-based routing has better compatibility; History API-based routing is more formal, and can set any URL of the same origin as the current URL, making the path more intuitive. In addition, Hash-based routing does not need to make changes to the server, while routing based on History API needs to make some changes to the server, and configure different routes to return the same page.

vue-router

vue-router is a routing plugin for the Vue.js framework, which supports the routing settings in the above two ways.
The basic routing configuration of vue-router is as follows:

import Router from 'vue-router'
import Index from 'pages/index'
import Error from 'pages/error'

Vue.use(Router)

export default new Router({
 mode: 'history', // 设置路由方式
 routes: [
   {
     path: '/',
     name: 'index',
     component: Index
   },
   {
     path: '*',
     name: '404',
     component: Error
   }
 ]
})

// 在组件中使用router视图组件
<router-view></router-view>

The routing rule list can be configured through the vue-router instance, and the corresponding relationship between the path path and the component component can be specified. The implementation mode of the route can be controlled through the parameter mode. The default value is hashthe hash-based implementation. If the display is set to history, it will be set to the history API-based implementation. If the browser does not support it, fallback can be set to control whether Need to rollback to 'hash' mode. In addition, if it is running on a non-browser side (such as in nodejs), the mode will be forced to 'abstract' mode.
vue-router supports routing nesting, dynamic routing configuration, redirection and aliases, etc., please refer to the official documentation .

react-router

react-router is developed based on the api provided by the history module. Its routing configuration is carried out through the react component method, as follows:

render((
  <Router history={browserHistory}>
    <Route path="/" component={App}>
      <Route path="about" component={About}/>
      <Route path="users" component={Users}>
        <Route path="/user/:userId" component={User}/>
      </Route>
      <Route path="*" component={NoMatch}/>
    </Route>
  </Router>
), document.body)

// link 触发路由
<Link to={`/user/89757`}>'joey'</Link>

The above declares a routing table with each mapping of path to component. Router uses this.history.listen to register the url update callback function in the hook componentWillMount of the react component life cycle (before the component is mounted). The callback function will be triggered when the url is updated, and the setState in the callback will render the new component.

router in NEJ

NEJ is also a front-end framework that supports single-page applications, and its module scheduling system can be used to support functions such as system architecture, module splitting and reorganization, and module scheduling management of single-page rich applications. As shown below, configure the mapping relationship between modules and routes through dispatcher to implement single-page applications.

NEJ.define([
    'util/dispatcher/dispatcher'
],function(_e,_p){
    // 取调度器实例
    var dispatcher = _p._$$Dispatcher._$getInstance();
    
    // start up dispatcher
    dispatch._$startup({
        rules: {
            rewrite: {
                404: '/m/overview/'
            },
            title: {
                '/m/overview/': '概览'
            },
            alias: {
                tab: '/?/tab/',
                layout: '/m',
                overview: '/m/overview/'
            }
        },
        modules: {
            '/?/tab/': 'module/tab/index.html',// 私有模块
            '/m/overview/': 'module/overview/index.html',
            '/m': {
                module: 'module/layout/index.html',
                composite: {
                    tab: '/?/tab/'
                }
            }
        },
        onbeforechange: function(options) {
            var umi = options.path || '';
            if (!!umi && umi.indexOf('/?') < 0 && umi.indexOf('/m') < 0) {
                options.path = '/m' + umi;
            }
        }
    });
})

The defined module refers to an independent unit separated from the system that can interact with the user to complete a part of the complete function, including the style, structure and functional logic of the module. In order to identify the module, a set of UMI (Uniform Module Identifier) ​​unified module identifier is adopted. For example /m/m0, each UMI can uniquely identify a module and its dependencies in the system. And the modules are divided into two types: modules that provide containers and modules that use containers, realizing any combination between modules. Its routing configuration is the mapping relationship between path and module, and the bottom layer is also implemented based on hash.

finally

With the increasing performance of browsers, there are more and more single-page applications in today's world where more and more attention is paid to user experience and quick response. Whether you use the router plugin of popular front-end frameworks or implement it yourself, it is necessary to have a comprehensive understanding of front-end routing and its implementation mechanism.

references

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324983393&siteId=291194637