Здесь вы создадите динамическое веб-приложение, используя минимальный HTML и взамен используя объектную модель документа (DOM) и JavaScript.

Почему? Почему я не могу просто написать HTML, CSS, связать их вместе, и у меня есть свой сайт ?! Да, да, может показаться, что я делаю вещи более сложными, чем необходимо, но эффективность одностраничных приложений может сэкономить время позже при разработке динамических веб-приложений, особенно при внесении изменений.

Есть много вариантов решения этой проблемы, наиболее очевидный из которых - с точки зрения браузера (например, chrome, firefox…). Если у вас есть динамическое веб-приложение с множеством страниц материалов, вероятно, где-то есть повторяющийся код (например, на панели навигации, нижнем колонтитуле и т. Д.). Когда вы перемещаетесь по этим страницам, браузер будет обновлять страницу каждый раз, перезагружая контент, который уже был загружен на предыдущей странице. Это просто лишняя работа для браузера, которая может ухудшить взаимодействие с пользователем; секунды, потраченные впустую на перезагрузку страницы, могут привести к покупке покупателю или сорвать его.

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

Создайте шаблон для своей главной страницы, тот, который будет загружен первым, и мы будем строить только на нем. Назовем это index.html

<-- in index.html -->
<html>
  <head>
    <meta charset="utf-8">
    <title>Navigation Example</title>
  </head>
  <body>
    <a href="">Home</a>
    <a href="">About</a>
    <a href="">Contact</a>

  </body>
</html>

Предполагая, что вы уже знаете HTML, вы будете знать, что теги «a» являются ссылками. Обычно они перенаправляют вас на другую страницу сайта, если мы помещаем URL в атрибуты href.

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

<-- in index.html -->
<html>
  <head>
    <meta charset="utf-8">
    <title>Navigation Example</title>
  </head>
  <body>
    <a href="#home">Home</a>
    <a href="#about">About</a>
    <a href="#contact">Contact</a>

  </body>
</html>

Идентификатор фрагмента (#home, #about и т. Д.) Используется только для идентификации части документа, например привязки. Запустите index.html и щелкните по ссылкам. URL-адрес в вашем URL-адресе изменится, но страница не будет перезагружена.

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

Создайте новый файл с именем main.js и свяжите с ним index.html с помощью тегов скрипта.

// in main.js

console.log(location.hash)

Console.log выведет на консоль значения, заключенные в скобки. Чтобы увидеть консоль, щелкните правой кнопкой мыши страницу своего браузера и выберите «проверить элемент», хотя это может отличаться в зависимости от вашего браузера. Инструменты разработчика Chrome, как известно, являются фаворитом среди разработчиков.

Location.hash - это идентификатор фрагмента, о котором мы говорили ранее. Если мы поместим хэш в конец строки запроса (URL-адрес) и нажмем Enter, консоль распечатает идентификатор фрагмента. Круто, но это бесполезно. Давайте попробуем следующее:

// This will listen for the fragment identifier change
window.addEventListener("hashchange", function() {
  console.log(location.hash);
});

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

Если вы нажмете на домашнюю ссылку, запускается прослушиватель событий, поскольку URL-адрес теперь имеет другой идентификатор фрагмента. Получите это значение с помощью location.hash и распечатайте его на консоли. Попробуйте и посмотрите, как каждый из идентификаторов фрагментов выводится на консоль каждый раз, когда вы нажимаете ссылку.

Теперь console.log немного утомителен, но всегда хорош, чтобы что-то попробовать, но позволяет вывести его на страницу, чтобы все могли увидеть. Во-первых, давайте вернемся к index.html и создадим заполнитель для будущего текста.

<-- in index.html -->

<html>
  <head>
    <meta charset="utf-8">
    <title>Navigation Example</title>
  </head>
  <body>
    <a href="#home">Home</a>
    <a href="#about">About</a>
    <a href="#contact">Contact</a>

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

Я добавил элемент div с идентификатором app. Сначала это пусто, и мы добавим в него кое-что позже. Думайте об этом как о пустой коробке, сейчас она пуста, но вы всегда можете упаковать ее и распаковать, чем захотите. Давайте упакуем его текстом с помощью JS

// in main.js

window.addEventListener("hashchange", function (){
  var contentDiv = document.getElementById("app");
  contentDiv.innerHTML = location.hash;
});

Скопируйте код и перейдите в браузер. Когда вы щелкаете ссылку, на странице должен отображаться идентификатор фрагмента в документе, без необходимости перезагрузки страницы. Простой.

Единственная проблема, с которой мы сейчас сталкиваемся, заключается в том, что когда мы переходим на такую ​​страницу, как yourdocument.html # about, прослушиватель событий не работает, потому что документ загружается. Заметили проблему? У нас будет пустая страница даже при наличии идентификатора фрагмента. Мы хотим, чтобы страница загружала контент на основе идентификатора фрагмента даже без использования прослушивателя событий. Взгляните на следующее.

// in main.js
function loadContent(){
  var contentDiv = document.getElementById("app");
  contentDiv.innerHTML = location.hash;
}

window.addEventListener("hashchange", function (){
  loadContent();
});

loadContent();

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

Взгляните на код и посмотрите, сможете ли вы отредактировать его еще больше, особенно в прослушивателе событий. Взглянем:

// in main.js
function loadContent(){
  var contentDiv = document.getElementById("app");
  contentDiv.innerHTML = location.hash;
}


window.addEventListener("hashchange", loadContent);

loadContent();

Мы делаем успехи, но у нас все еще есть небольшая проблема, первая страница без идентификатора фрагмента остается пустой, но она должна быть домашней, верно? Сделайте следующее:

// in main.js
function loadContent(){
  var contentDiv = document.getElementById("app");
  contentDiv.innerHTML = location.hash;
}

if(!location.hash) {
  location.hash = "#home";
}

loadContent();

window.addEventListener("hashchange", loadContent)

Теперь у нас есть оператор if. Давайте посмотрим на это изолированно:

if(!location.hash){
    location.hash = "#home";
}

По сути, это говорит: «Если хеша местоположения нет, сделайте хеш местоположения #home». в начале location.hash отменяет выражение.

Нам нужно решить еще одну вещь: мы не хотим распечатывать символ решетки вместе со страницей. Давайте разберемся с этим с помощью метода JS под названием substr.

// in main.js
function loadContent(){
  var contentDiv = document.getElementById("app"),

      // This gets rid of the first character of the string
      fragmentId = location.hash.substr(1);

  contentDiv.innerHTML = fragmentId;
}

if(!location.hash) {
  location.hash = "#home";
}


loadContent();

window.addEventListener("hashchange", loadContent)

Метод substr удаляет первую букву строки и возвращает остальные. Это приводит к удалению символа # из идентификатора фрагмента.

Все это очень хорошо распечатывает идентификатор фрагмента, но это немного скучно, нет интересного контента, чтобы действительно продемонстрировать ваш сайт.

function getContent(fragmentId){

// lets do some custom content for each page of your website
  var pages = {
    home: "This is the Home page. Welcome to my site.",
    about: "This page will describe what my site is about",
    contact: "Contact me on this page if you have any questions"
  };

// look up what fragment you are searching for in the object
  return pages[fragmentId];
}

function loadContent(){

  var contentDiv = document.getElementById("app"),
      fragmentId = location.hash.substr(1);

  contentDiv.innerHTML = getContent(fragmentId);
}

if(!location.hash) {
  location.hash = "#home";
}

loadContent();

window.addEventListener("hashchange", loadContent)

Здесь у нас есть новая функция под названием getContent. Требуется аргумент fragmentId. Внутри этой функции у нас есть объект JS, который похож на словарь. Он заполнен парами ключ-значение, такими как слово и описание. В нашем случае это название страницы и связанный с ней контент. Я назвал страницы объекта.

Внизу функции мы ищем объект partials, передавая ему значение fragmentId (это страница, на которой мы находимся). Затем браузер выполняет итерацию по объекту partials и возвращает нам соответствующее значение. Мы на шаг ближе к динамическому сайту.

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

function getContent(fragmentId, callback){

  var pages = {
    home: "This is the Home page. Welcome to my site.",
    about: "This page will describe what my site is about",
    contact: "Contact me on this page if you have any questions"
  };

  callback(pages[fragmentId]);
}



function loadContent(){

  var contentDiv = document.getElementById("app"),
      fragmentId = location.hash.substr(1);

  getContent(fragmentId, function (content) {
    contentDiv.innerHTML = content;
  });

}

if(!location.hash) {
  location.hash = "#home";
}

loadContent();

window.addEventListener("hashchange", loadContent)

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