Front-end routing principle and implementation

Introduction to the principle of vue-router

In a nutshell, when using $router.push and $router.replace, call the location.href and location.replace methods of the window, use the hashchage and statechange events of the window to monitor the page routing changes, and load the corresponding routing module according to the url.

Two modes of vue-router

Vue-router has two modes, one is histroy mode (without "#"), and the other is hash mode (with "#").
What is hash? The Chinese meaning is the anchor point. If you remember the basics of html, you should know what it is. Here is a simple example for students who have forgotten the basic knowledge

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>浏览器路由</title>
    <style>
      div{
      
      height: 500px; text-align: center;line-height: 500px; font-size: 40px;}
    </style>
  </head>
  <body>
    
    <div style="background: yellow;">
      <a href="#/1f">跳转到一楼</a>
      <a href="#/2f">跳转到二楼</a>
    </div>
    <div style="background: yellowgreen;">一楼<a name="/1f"></a></div>
    <div style="backgrour nd: green;">二楼<a name="/2f"></a></div>
  </body>
</html>

Click the a tag to know that the hash mode just jumps to a certain part of the page, it will change the url of the browser, but it will not jump to other pages, so the operation will be easier.

The operation of history mode will be more complicated, because it needs to consider the configuration of the server and the storage path of the front-end files.

Taking nginx as an example, when you visit localhost:80/, you actually visit html/index.html. When your link is localhost:80/router/ (note that router.html is found by default without a slash), in fact It will visit html/router/index.html, that is to say, if there is no index.html in this path, it will 404, so there is an nginx configuration on the vue-router official website

location / {
    
    
  try_files $uri $uri/ /index.html;
}

It means that if your link is loaclhost:80/xxx, regardless of whether xxx is router/ or router/router1/, you will visit html/index.html
insert image description here

If your code is not directly placed in html but html/baseUrl, your vue and nginx have to be configured separately, see vue-router official website for details

Simple implementation of vue-router

For a simpler understanding, this article only introduces the implementation of the hash mode. The principle of history mode is similar to that of hash mode, one is to monitor hashchange and the other is to monitor statechange. Complete code address
代码很简单,就不过多介绍了,直接看代码吧
1. Directly upload dozens of lines of code to implement a simple vue-router

class VueRouter {
    
    
    // 接收router配置以及router挂载的dom
    constructor(routers, $el){
    
    
        // 路由加监听
        window.addEventListener('hashchange',(evt)=>{
    
    
            console.log(evt); // 可以看看都有啥
            let hash = location.hash.substring(1);
            this.renderRouter(hash);
        })
        this.routers = routers;
        this.$el = $el;
        // 在webpack打包中的window模式下,会把router模块挂载在window下
        this.routerId = 'routerId'
    }
    replace(path){
    
    
        // 省略亿点点细节
        location.replace( getRealUrl(path) )
    }
    // 找到对应的router后挂载到页面上
    renderRouter(path) {
    
    
        // 不考虑子路由,可以省略亿点点细节
        this.routers.some((val)=>{
    
    
            if(val.path === path ) {
    
    
                this.loadrouter(val.component)
            }
            return val.path === path
        })
    }
    // 将router里的内容挂载出来
    async loadrouter(component) {
    
    
        const chunks = window[`webpackJson_${
      
      this.routerId}`];
        let chunk = null;
        // 在chunk中查找component
        chunks.some(item=>{
    
    
            if(item[0] === component.webpackChunkName) {
    
    
                chunk = item
            }
            return item[0] === component.webpackChunkName
        })
        // 没有加载的js,懒加载
        if(!chunk){
    
    
            await loadScript(component.url);
            chunk = chunks[chunks.length-1];
        }
        // 替换掉router中的内容
        document.querySelector(this.$el).innerHTML= chunk[1].html;
    }
}
// push是js默认属性,需要重写
VueRouter.prototype.push = (path)=>{
    
    
    location.href = getRealUrl(path);
}
// 将path处理为真实可用的url
var getRealUrl = (path)=>{
    
    
    return `${
      
      location.href.substring(0,location.href.indexOf('#') )}#${
      
      path}`
}
// 懒加载js
var loadScript = async (url) => {
    
    
    return new Promise((resolve, reject) => {
    
    
        const script = document.createElement('script');
        script.src = url;
        script.onload = resolve;
        script.onerror = reject;
        const head = document.getElementsByTagName('head')[0];
        head.appendChild(script);
    });
};

2. Use

// webpack的打包输出,如果output设置为window,打包出来的模块就会挂载在window上
(window["webpackJson_routerId"] = window["webpackJson_router"] || []).push([
    "router1", {
    
    
        html: `<div style="width:100px;height:100px;background:yellowgreen" id="router1">router1<div>`,
        methods: {
    
    
            method_1(){
    
    },
            method_2(){
    
    },
        }
    }
])
// 实例化
var router = new VueRouter([
    {
    
    
        path: '/router1',
        // vue的component最终的表现是一个js文件或者是一个js模块,取决于你怎么打包
        component: {
    
    
            webpackChunkName: 'router1',
        }
    },
    {
    
    
        path: '/router2',
        component: {
    
    
            webpackChunkName: 'router2',
            url: './router2.js'
        }
    },
], '.router')

function gotoRouter(){
    
    
    router.push('/router1')
}
function replaceRouter(){
    
    
    router.replace('/router2')
}

3. HTML part

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>浏览器路由</title>
    <style>
      .router{
      
      height: 500px; text-align: center;line-height: 500px; font-size: 40px; background: aqua;}
    </style>
  </head>
  <body>
    <div>
      <button onclick="gotoRouter()">跳转到一楼</button>
      <button onclick="replaceRouter()">跳转到二楼</button>
    </div>
    <div class="router">

    </div>
  </body>
  <script src="./router.js"></script>
  <script src="./app.js">
  </script>
</html>

Guess you like

Origin blog.csdn.net/qq_38217940/article/details/123973074