Один из наиболее часто задаваемых вопросов по коду во время фронтенд-интервью: «Можете ли вы создать одностраничное приложение с маршрутами без фреймворка?» В этом руководстве я покажу вам, как создать пользовательскую систему маршрутизации для вашего одностраничного приложения, используя метод хеширования или URL… без фреймворка.

В этом руководстве показано, как создать одностраничное приложение с использованием ванильного JavaScript. Я покажу вам, как реализовать маршрутизацию на стороне клиента в обоих направлениях (хэш или URL) в удобном для использования формате, который можно воспроизвести для любого проекта.

Посмотреть это на YouTube

Структура папок

Мы используем базовую структуру HTML. Вы можете настроить свои файлы так, как вам нравится, но ради этого урока вы можете воспроизвести то, что есть у меня ниже.

index.html
/templates
   404.html
   index.html
   about.html
   contact.html
/js/
   router.js

Давайте создадим наш HTML

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

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title></title>
   </head>
   <body>
      <nav>
      </nav>
      <div id="content"></div>
   </body>
</html>

Создание JS-файла

Перед закрывающим тегом </body> вам нужно добавить эту ссылку в файл JS, который вы создали выше.

<script src="/js/router.js"></script>

Вариант первый: URL-маршрутизация

Сначала мы рассмотрим, как это сделать с помощью маршрутизации URL. Это означает, что ваши ссылки будут выглядеть как /about. Это типичный вид URL. хеш-метод использует # для разбиения страниц. Я расскажу об этом ниже.

Случай использования: веб-сайты

Этот вариант лучше для SEO и более удобен для пользователя.

ПРИМЕЧАНИЕ. Этот метод имеет некоторые недостатки. Вам необходимо настроить веб-сервер для обслуживания index.html для путей маршрутов SPA. Вы можете сделать это на уровне сервера, но если вы используете что-то вроде VS Code LIVE SERVER, вы не сможете. Это означает, что если вы перейдете непосредственно к /about, сервер не будет отображать файл, поскольку ему необходимо сначала загрузить сценарии index.html. Для этого вы можете изменить файл .htaccess.

Добавьте HTML-навигацию

Добавьте следующее между тегами <nav></nav> в файле index.html.

<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>

Добавьте навигационные ссылки в HTML

Теперь приступим к JS. Во-первых, мы хотим, чтобы любая ссылка в тегах <nav></nav> использовала нашу маршрутизацию.

// create document click that watches the nav links only
document.addEventListener("click", (e) => {
    const { target } = e;
    if (!target.matches("nav a")) {
        return;
    }
    e.preventDefault();
    route();
});

Создайте маршруты

Каждый маршрут будет иметь связанный с ним массив объектов. Это сообщит сценарию, что такое URL-ссылка, а также какой шаблон, заголовок и описание следует использовать.

const routes = {
    404: {
        template: "/templates/404.html",
        title: "404",
        description: "Page not found",
    },
    "/": {
        template: "/templates/index.html",
        title: "Home",
        description: "This is the home page",
    },
    "/about": {
        template: "/templates/about.html",
        title: "About Us",
        description: "This is the about page",
    },
    "/contact": {
        template: "/templates/contact.html",
        title: "Contact Us",
        description: "This is the contact page",
    },
};

Создайте функцию, которая отслеживает URL-адрес и вызывает urlLocationHandler.

const route = (event) => {
    event = event || window.event; // get window.event if event argument not provided
    event.preventDefault();
    // window.history.pushState(state, unused, target link);
    window.history.pushState({}, "", event.target.href);
    locationHandler();
};

Создайте функцию, которая обрабатывает местоположение URL

const locationHandler = async () => {
    const location = window.location.pathname; // get the url path
    // if the path length is 0, set it to primary page route
    if (location.length == 0) {
        location = "/";
    }
    // get the route object from the urlRoutes object
    const route = routes[location] || routes["404"];
    // get the html from the template
    const html = await fetch(route.template).then((response) => response.text());
    // set the content of the content div to the html
    document.getElementById("content").innerHTML = html;
    // set the title of the document to the title of the route
    document.title = route.title;
    // set the description of the document to the description of the route
    document
        .querySelector('meta[name="description"]')
        .setAttribute("content", route.description);
};

Завершение сценария

Наконец, нам нужно вызвать функцию при первой загрузке страницы, иначе домашняя страница не будет работать, если на нее не щелкнуть. Нам также нужно добавить наблюдатель за изменениями URL, чтобы скрипт знал, когда показывать новый контент.

// add an event listener to the window that watches for url changes
window.onpopstate = locationHandler;
// call the urlLocationHandler function to handle the initial url
window.route = route;
// call the urlLocationHandler function to handle the initial url
locationHandler();

Вариант второй: хэш-маршрутизация

Если вы используете метод хеширования, замените содержимое файла router.js следующим кодом.

Теперь о втором варианте. Хеш-маршрутизация более распространена, если вы используете фреймворк, но если вы создаете его с нуля, отрицательное преимущество SEO может заставить вас уклоняться. Это означает, что ваши ссылки будут выглядеть как #about вместо типичного метода URL, описанного выше. Для некоторых этот тип URL-адреса может быть не оптимальным из-за того, что он сильно отличается от того, к чему привыкли ваши пользователи. В остальном код очень похож на метод URL... даже короче.

Применение: приложения, целевые страницы

ПРИМЕЧАНИЕ. Этот метод имеет некоторые недостатки. использование хэшей может быть не лучшим способом для SEO, а также может быть необычным для некоторых пользователей, из-за чего они могут не использовать веб-сайт.

Добавьте HTML-навигацию

Добавьте следующее между тегами <nav></nav> в файле index.html.

<a href="/">Home</a>
<a href="#about">About</a>
<a href="#contact">Contact</a>

Создайте маршруты

Хэш-маршруты очень похожи на URL-маршруты выше. Вы можете повторно использовать эту часть скрипта. Разница в основном заключается в том, как определяется ключ ссылки маршрута.

const routes = {
    404: {
        template: "/templates/404.html",
        title: "404",
        description: "Page not found",
    },
    "/": {
        template: "/templates/index.html",
        title: "Home",
        description: "This is the home page",
    },
    about: {
        template: "/templates/about.html",
        title: "About Us",
        description: "This is the about page",
    },
    contact: {
        template: "/templates/contact.html",
        title: "Contact Us",
        description: "This is the contact page",
    },
};

Создайте функцию, которая обрабатывает местоположение URL

const locationHandler = async () => {
    // get the url path, replace hash with empty string
    var location = window.location.hash.replace("#", "");
    // if the path length is 0, set it to primary page route
    if (location.length == 0) {
        location = "/";
    }
    // get the route object from the routes object
    const route = routes[location] || routes["404"];
    // get the html from the template
    const html = await fetch(route.template).then((response) => response.text());
    // set the content of the content div to the html
    document.getElementById("content").innerHTML = html;
    // set the title of the document to the title of the route
    document.title = route.title;
    // set the description of the document to the description of the route
    document
        .querySelector('meta[name="description"]')
        .setAttribute("content", route.description);
};

Завершение сценария

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

// create a function that watches the hash and calls the urlLocationHandler
window.addEventListener("hashchange", locationHandler);
// call the urlLocationHandler to load the page
locationHandler();

Заключение

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