Вот список моих лучших руководств по веб-разработке.

Полное руководство по CSS-гибкости на Hashnode.

Ultimate CSS grid tutorial на Hashnode.

Функции высшего порядка .map, .filter и .reduce на Hashnode.

Подписывайтесь на меня в @ Twitter, Instagram и fb, чтобы никогда не пропустить премиум-статьи.



Когда вы думаете о маршрутизаторах, вы обычно думаете о таких библиотеках, как React. Но внутри этих библиотек и фреймворков по-прежнему используется обычный JavaScript. Так как они это делают? Я надеюсь, что это руководство по маршрутизатору JavaScript поможет вам понять, как собрать свой собственный маршрутизатор JS.

Создать собственный маршрутизатор на ванильном JavaScript относительно просто, если вы понимаете все отдельные части, участвующие в его создании.

Основные моменты. Вот основные моменты создания собственного js-маршрутизатора:

  1. Прослушивание события «popstate» для ответа на изменение пути. Это происходит всякий раз, когда новый URL вводится в адресную строку браузера, но мы не хотим обновлять страницу, просто обновите представление, загрузив новое содержание.
  2. Базовое понимание history и history.pushState (API истории JavaScript), если вы хотите интегрировать свой маршрутизатор в собственную архитектуру браузера.

Краткий обзор JavaScript History API

Я видел так много руководств по vanilla js router, в которых не упоминается JavaScript History API. Очень жаль, потому что нажатие кнопок браузера Назад и Вперед имеет прямое отношение к переходу между URL-адресами в истории просмотров. Невозможно говорить о маршрутизации без History API.

  1. history.back () аналогично history.go (-1) или когда пользователь нажимает кнопку Назад в своем браузере. Вы можете использовать любой из этих методов с одинаковым эффектом.
  2. history.forward () выполняется, когда пользователь нажимает кнопку Вперед в браузере, и это эквивалентно history.go (1)
  3. go () аналогичен методам .back () и forward (), за исключением того, что вы можете указать, на сколько шагов назад или вперед вы хотите перейти. в стеке истории браузера.
  4. pushState () отправит новое состояние в API истории.
  5. Свойство .length - это количество элементов в истории сеанса.
  6. Свойство .state используется для поиска состояния без прослушивания события «popstate».

Хорошо, давайте начнем с нашей собственной реализации ванильного js-роутера!

Я просто выгружу минимум HTML, CSS и JavaScript с комментариями. А затем я добавлю ссылку на исходный код в формате GIF и GitHub.

История настройки Vanilla JS Router на основе API

Давайте рассмотрим минимальный код, необходимый для создания переключателя URL (без обновления страницы), а затем я покажу вам GIF-файл, показывающий, как все это работает.

<html>
<head>
    <title>Hello</title>
    <script type = "module">
            function select_tab(id) {
                // Remove selected class from all buttons
                document.querySelectorAll(".route").forEach(
                    item => item.classList.remove('selected'));
                // select clicked element (visually)
                document.querySelectorAll("#" + id).forEach(
                    item => item.classList.add('selected'));
            }
            function load_content(id) {
                console.log("Loading content for {" + id + "}");
                // Update text "Content loading for {id}..."
                // Here you would do content loading magic...
                // Perhaps run Fetch API to update resources
                document.querySelector("#content").innerHTML
                  = 'Content loading for /' + id + '...';
            }
            function push(event) {
                // Get id attribute of the button or link clicked
                let id = event.target.id;
                // Visually select the clicked button/tab/box
                select_tab(id);
                // Update Title in Window's Tab
                document.title = id;
                // Load content for this tab/page
                load_content(id);
                // Finally push state change to the address bar
                window.history.pushState({id}, `${id}`,
                                      `/page/${id}`);
            }
            window.onload = event => {
                // Add history push() event when boxes are clicked
                window["home"].addEventListener("click",
                event => push(event))
                window["about"].addEventListener("click",
                event => push(event))
                window["gallery"].addEventListener("click",
                event => push(event))
                window["contact"].addEventListener("click",
                event => push(event))
                window["help"].addEventListener("click",
                event => push(event))
            }
            // Listen for PopStateEvent
            // (Back or Forward buttons are clicked)
            window.addEventListener("popstate", event => {
                // Grab the history state id
                let stateId = event.state.id;
                // Show clicked id in console (just for fun)
                console.log("stateId = ", stateId);
                // Visually select the clicked button/tab/box
                select_tab(stateId);
                // Load content for this tab/page
                load_content(stateId);
            });
        </script>
    <style>
            * { /* global font */
                font-family: Verdana;
                font-size: 18px;
            }
            #root { display: flex; flex-direction: row; }
            #content { display: flex;
                display: block;
                width: 800px;
                height: 250px;
                /* vertically centered text */
                line-height: 250px;
                border: 2px solid #555;
                margin: 32px;
                text-align: center;
            }
            .route {
                cursor: pointer;
                justify-content: center;
                width: 150px;
                height: 50px;
                /* vertically centered text */
                line-height: 50px;
                position: relative;
                border: 2px solid #555;
                background: white;
                text-align: center;
                margin: 16px;
            }
            .route.selected { background: yellow; }
        </style>
</head>

<body>

<section id = "root">
    <section class = "route" id = "home">/home</section>
    <section class = "route" id = "about">/about</section>
    <section class = "route" id = "gallery">/gallery</section>
    <section class = "route" id = "contact">/contact</section>
    <section class = "route" id = "help">/help</section>
</section>

<main id = "content">Content loading...</main>

</body>

</html>

В основе лежит вызов window.history.pushState ({id}, $ {id}, / page / $ { id});

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

Результаты. Теперь каждый раз, когда мы нажимаем кнопку, URL-адрес в адресной строке браузера будет фактически изменяться. Поле содержимого тоже обновляется.

Вы можете разветвить мой GitHub (router.html) в моей vanilla js library.

Конечно, нам также необходимо загрузить контент с сервера, ссылаясь на макеты и ресурсы для этого места. Это зависит от вашего приложения!

Как заставить работать кнопки "Назад" и "Вперед"

Используя history.pushState, вы автоматически заставляете кнопки Назад и Вперед переходить к предыдущее или следующее состояние. При этом создается событие popstate. Это та часть, где вы должны еще раз обновить свое представление. (В первый раз мы нажали кнопку.) Но поскольку событие содержит идентификатор того, что было нажато, легко обновить представление и перезагрузить контент, когда Назад или Вперед:

Мы не используем здесь React или Vue, поэтому в моем исходном коде load_content позаботится об обновлении представления непосредственно в DOM. Эта область, вероятно, будет заполнена некоторым контентом, загруженным из вашего API. Поскольку это всего лишь пример внешнего интерфейса, я мало что могу сделать, чтобы показать вам, как это сделать. Но именно так это работает на стороне клиента.

Первоначальная загрузка маршрутизатора со стороны сервера

Чтобы собрать все это воедино, требуется еще один шаг. В моем примере я просто использовал router.html. Когда вы впервые загружаете этот маршрутизатор в PWA, вы должны убедиться, что он работает, если, скажем, / page / home был введен непосредственно в адресную строку.

До сих пор мы меняли адрес маршрутизатора только из внешнего интерфейса. Предполагается, что каждый раз, когда вы переходите к URL-адресу, который отображается на кнопках нашего маршрутизатора, он будет загружаться с сервера отдельно.

Поэтому вы обязаны убедиться. Например, / page / about загрузит маршрутизатор и связанный с ним контент. / page / about в какое-то корневое представление. (А также выделите «текущую» кнопку / вкладку.)

Как только вы реализуете эту часть, ваш маршрутизатор будет готов. То, как вы решите перезагрузить контент в элементе #content, полностью зависит от вашего внутреннего дизайна.