Познакомьте вас с основными принципами маршрутизации, напишите маршрут с помощью нативного js.

JavaScript

Основная функция маршрутизации — обеспечить синхронизацию представлений и URL-адресов, а представления можно рассматривать как представление ресурсов.

В настоящее время основные внешние интерфейсы Vue, React и Angular предоставляют плагины для маршрутизации. Вообще говоря, эти плагины маршрутизации всегда предоставляют два разных метода маршрутизации: Hash и History. Конкретное содержание будет упомянуто ниже.Давайте просто напишем маршрут вокруг этих двух методов:

1. Хэш-режим

Основные понятия хэша: метод Hash заключается в наличии # в маршруте.Основной принцип заключается в отслеживании события hashchange браузера, вызванного изменением идентификатора пути URL-адреса после #, а затем получения текущего идентификатора пути путем получения location.hash, а затем do some О маршрутизации операций перехода см.MDN

Сначала создаем файл index.html и запускаем запись хеша в тег body:

<button type="button" onclick="history.go(-1)">返回</button>
<h2>push模式</h2>
<ul>
    <li onclick="Router.push('/')">首页</li>
    <li onclick="Router.push('/news')">新闻</li>
    <li onclick="Router.push('/product')">产品</li>
</ul>
<div id="app"></div>
<script>
    var app = document.getElementById("app");

    function RouterClass() {
        this.routes={};
        this.curUrl=""; //初始url
        this.eventHashRouter();
    }

    RouterClass.prototype.route = function(path, callback) {
        this.routes[path] = callback || function(){}
    }

    // 监听hash模式路由
    RouterClass.prototype.eventHashRouter = function() {
        window.addEventListener("hashchange", this.hashRouter.bind(this))
    }

    RouterClass.prototype.hashRouter = function() {
        this.curUrl = window.location.hash.slice(1) || '/';
        // console.log(this.curUrl);
        this.routes[this.curUrl]();
    }

    // push模式页面跳转
    RouterClass.prototype.push = function(url) {
        console.log(url);
        url = "#" +url;
        window.location.href = url;
    }

    var Router = new RouterClass() //初始化 使用

    // 构造一个函数,根据url 改变 #app 中的内容,对页面进行渲染
    Router.route('/', function() {
        app.innerHTML="首页"
    })
    Router.route('/news', function() {
        app.innerHTML="新闻页面"
    })
    Router.route('/product', function() {
        app.innerHTML="产品页面"
    })
</script>

Таким образом, в основном реализуется маршрутизация хеш-режима.Обычно нажатие на домашнюю страницу, новости и товары должно отображать соответствующую информацию в #app, но здесь есть небольшая ошибка, то есть когда страница обновляется, данные будут потеряны. Кроме того, push сам запишет вашу запись кликов.Когда вы захотите вернуться через кнопку «Назад», он вернется в соответствии с вашей записью кликов, что делает невозможным возврат на домашнюю страницу напрямую через кнопку возврата после нажатия многих pages., здесь нам нужно использовать replace, чтобы решить эту проблему.

Далее, давайте решим две вышеупомянутые проблемы, см. следующий код:

<h2>replace模式</h2>
<ul>
    <!-- hash模式 就是带 # 号的 -->
    <li onclick="Router.replace('/')">首页</li>
    <li onclick="Router.replace('/news')">新闻</li>
    <li onclick="Router.replace('/product')">产品</li>
</ul>
// 监听hash模式路由
RouterClass.prototype.eventHashRouter = function() {
    // 监听load事件,防止刷新页面数据丢失
    window.addEventListener("load", this.hashRouter.bind(this));
    window.addEventListener("hashchange", this.hashRouter.bind(this))
}

//replace模式页面跳转
RouterClass.prototype.replace = function(url) {
    url = "#" +url;
    window.location.replace(url);
}

Поздравляем, проблема решена, на данный момент хеш-режим маршрутизации успешно завершен.

2. Режим истории

Далее, давайте взглянем на другой исторический режим маршрутизации.

Давайте изменим наш текущий код:

<script>
    // baseUrl 是根路径
    var app = document.getElementById("app"), baseUrl = "/router/";

    function RouterClass(opts) {
        this.routes={};
        this.curUrl="";
        this.mode=""; 
        if(opts){
            this.mode=opts.mode;
            if(this.mode==='history'){
                this.eventHistoryRouter();
            }else{
                this.eventHashRouter();
            }
        }else {
            this.eventHashRouter();
        }
    }

    RouterClass.prototype.route = function(path, callback) {
        this.routes[path] = callback || function(){}
    }

    // 监听hash模式路由
    RouterClass.prototype.eventHashRouter = function() {
        // 监听load事件,防止刷新页面数据丢失
        window.addEventListener("load", this.hashRouter.bind(this));
        window.addEventListener("hashchange", this.hashRouter.bind(this))
    }

    //hash模式
    RouterClass.prototype.hashRouter = function() {
        this.curUrl = window.location.hash.slice(1) || '/';
        // console.log(this.curUrl);
        this.routes[this.curUrl]();
    }

    // history模式
    RouterClass.prototype.historyRouter = function() {
        this.curUrl = window.location.pathname;
        this.routes[this.curUrl]();
    }

    // 监听history模式
    RouterClass.prototype.eventHistoryRouter = function() {
        window.addEventListener("load", this.historyRouter.bind(this));
        // 监听回退事件  打个比方:就是你点浏览器那个返回的箭头按钮时触发的事件
        window.addEventListener("popstate", this.historyRouter.bind(this));
    }

    // push模式页面跳转
    RouterClass.prototype.push = function(url) {
        if(this.mode === 'history') {
            window.history.pushState({},null,url);
            this.routes[url]();
        }else{
            url = "#" +url;
            window.location.href = url;
        }
    }

    //replace模式页面跳转
    RouterClass.prototype.replace = function(url) {
        if(this.mode==='history'){
            window.history.replaceState({},null,url);
            this.routes[url]();
        }else {
            url = "#" + url;
            window.location.replace(url);
        }
    }

    var Router = new RouterClass({
        mode:"history"  //hash:带#号,history:不带#号
    });

    // 构造一个函数,根据url 改变 #app 中的内容,对页面进行渲染
    Router.route(baseUrl,function(){
        app.innerHTML="首页"
    })
    Router.route(baseUrl+'news',function(){
        app.innerHTML="新闻页面"
    })
    Router.route(baseUrl+'product',function(){
        app.innerHTML="产品页面"
    })
</script>

Позвольте мне добавить и объяснить методы history.pushState() и history.replaceState(), используемые для перехода между страницами в режиме истории. Эти два метода впервые появились в HTML5. Они могут соответственно добавлять и изменять записи истории. Более подробно вы можете обратиться к соответствующее объяснение на MDN:MDN.

Также напомню, если выДважды щелкните под прямой папкой, чтобы открыть htmlОн сообщит об ошибке следующим образом:

Это нужно запускать на сервере, и нормально кинуть html файл на сервер, я кидаю на апач и запускаю с апачем, и ошибка решается.

Думаете это конец?На самом деле баги еще есть.Если перепрошится с F5,то выдаст классику404 Not Found.

Как решить эту проблему?Для Apache ее можно решить настроив .htaccess:

<IfModule mod_rewrite.c>
  Options Indexes FollowSymLinks ExecCGI
  RewriteEngine On
  RewriteBase /
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /router/index.html [L]

    #ErrorDocument 404 /router/index.html
</IfModule>

Что вам нужно изменить, так это RewriteRule здесь, который переписывает URL-адрес, сохраните его как файл .htaccess и поместите его в папку Apache с вашим html, например:

Эти два элемента я положил в папку роутера.

Наконец-то мы завершили реализацию роутинга с помощью нативного js, поздравляю.

Наконец, давайте опубликуем полный код:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>手写router</title>
</head>
<body>
    <button type="button" onclick="history.go(-1)">返回</button>
    <h2>push模式</h2>
    <ul>
        <li onclick="Router.push(baseUrl)">首页</li>
        <li onclick="Router.push(baseUrl+'news')">新闻</li>
        <li onclick="Router.push(baseUrl+'product')">产品</li>
    </ul>
    <h2>replace模式</h2>
    <ul>
        <li onclick="Router.replace(baseUrl)">首页</li>
        <li onclick="Router.replace(baseUrl+'news')">新闻</li>
        <li onclick="Router.replace(baseUrl+'product')">产品</li>
    </ul>
    <div id="app"></div>
    <script>
        // baseUrl 是根路径
        var app = document.getElementById("app"), baseUrl = "/router/";

        function RouterClass(opts) {
            this.routes={};
            this.curUrl="";
            this.mode=""; 
            if(opts){
                this.mode=opts.mode;
                if(this.mode==='history'){
                    this.eventHistoryRouter();
                }else{
                    this.eventHashRouter();
                }
            }else {
                this.eventHashRouter();
            }
        }

        RouterClass.prototype.route = function(path, callback) {
            this.routes[path] = callback || function(){}
        }

        // 监听hash模式路由
        RouterClass.prototype.eventHashRouter = function() {
            // 监听load事件,防止刷新页面数据丢失
            window.addEventListener("load", this.hashRouter.bind(this));
            window.addEventListener("hashchange", this.hashRouter.bind(this))
        }

        //hash模式
        RouterClass.prototype.hashRouter = function() {
            this.curUrl = window.location.hash.slice(1) || '/';
            // console.log(this.curUrl);
            this.routes[this.curUrl]();
        }

        // history模式
        RouterClass.prototype.historyRouter = function() {
            this.curUrl = window.location.pathname;
            this.routes[this.curUrl]();
        }
    
        // 监听history模式
        RouterClass.prototype.eventHistoryRouter = function() {
            window.addEventListener("load", this.historyRouter.bind(this));
            // 监听回退事件  打个比方:就是你点浏览器那个返回的箭头按钮时触发的事件
            window.addEventListener("popstate", this.historyRouter.bind(this));
        }

        // push模式页面跳转
        RouterClass.prototype.push = function(url) {
            if(this.mode === 'history') {
                window.history.pushState({},null,url);
                this.routes[url]();
            }else{
                url = "#" +url;
                window.location.href = url;
            }
        }

        //replace模式页面跳转
        RouterClass.prototype.replace = function(url) {
            if(this.mode==='history'){
                window.history.replaceState({},null,url);
                this.routes[url]();
            }else {
                url = "#" + url;
                window.location.replace(url);
            }
        }

        //初始化 使用
        var Router = new RouterClass({
            mode:"history"  //hash:带#号,history:不带#号
        });

        // 构造一个函数,根据url 改变 #app 中的内容,对页面进行渲染
        Router.route(baseUrl,function(){
            app.innerHTML="首页"
        })
        Router.route(baseUrl+'news',function(){
            app.innerHTML="新闻页面"
        })
        Router.route(baseUrl+'product',function(){
            app.innerHTML="产品页面"
        })
    </script>
</body>
</html>

На этом все закончилось. Надеюсь, вы что-то почерпнете из этой статьи. Моя статья представляет собой подведение итогов процесса обучения. Если есть какие-то ошибки, укажите на них и спасибо за прочтение.

Ссылаться на:

history | MDN

hashchange | MDN

Manipulating the browser history | MDN

History Object -- Учебное пособие по стандарту JavaScript