フロントエンド ルーティングの原則と実装

フロントエンド ルーティングの原則と実装

vue-router の原理の紹介

簡単に言えば、$router.push と $router.replace を使用する場合、ウィンドウの location.href メソッドと location.replace メソッドを呼び出し、ウィンドウの hashchage イベントと statechange イベントを使用してページ ルーティングの変更を監視し、対応するURL に従ってモジュールをルーティングします。

vue-router の 2 つのモード

Vue-router には、histroy モード ("#" なし) と、hash モード ("#" あり) の 2 つのモードがあります
中国語の意味はアンカーポイントです.htmlの基本を覚えていれば、それが何であるかを知っているはずです.これは、基本的な知識を忘れた学生のための簡単な例です.

<!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>

a タグをクリックすると、ハッシュ モードはページの特定の部分にジャンプするだけで、ブラウザの URL が変更されますが、他のページにはジャンプしないため、操作が簡単になります。

履歴モードの操作は、サーバーの構成とフロントエンド ファイルの保存パスを考慮する必要があるため、より複雑になります。

nginx を例にとると、localhost:80/ にアクセスすると、実際には html/index.html にアクセスします. リンクが localhost:80/router/ の場合 (router.html はデフォルトでスラッシュなしで検出されることに注意してください) html/router/index.html にアクセスします。つまり、このパスに index.html がない場合は 404 になるため、vue-router の公式 Web サイトに nginx の構成があります。

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

これは、リンクが loaclhost:80/xxx の場合、xxx が router/ または router/router1/ であるかどうかに関係なく、html/index.html にアクセスすることを意味します。
ここに画像の説明を挿入

コードが html ではなく html/baseUrl に直接配置されている場合、vue と nginx を個別に構成する必要があります。詳細については、 vue-router の公式 Web サイトを参照してください。

vue-router の簡単な実装

理解を容易にするために、この記事ではハッシュ モードの実装のみを紹介します。履歴モードの原理は、ハッシュ モードの原理と似ています。1 つはハッシュの変更を監視することで、もう 1 つは状態の変更を監視することです。完全なコード アドレス
代码很简单,就不过多介绍了,直接看代码吧
1. 数十行のコードを直接アップロードして、単純な 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.使用する

// 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部分

<!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>

おすすめ

転載: blog.csdn.net/qq_38217940/article/details/123973074