Чистый JavaScript - создание реального приложения с нуля

Это сообщение было впервые опубликовано на CodingTheSmartWay.com.

Современные платформы JavaScript, такие как Angular, React и Vue.js, упрощают создание сложных одностраничных веб-приложений. Однако использование этих фреймворков не обязательно, и вы также можете использовать простой и чистый JavaScript. Это руководство проведет вас через пошаговые инструкции по созданию веб-приложения на чистом JavaScript.

Что мы собираемся построить

Приложение, которое мы собираемся создать в этом руководстве, выглядит следующим образом:

Это простое приложение для отслеживания проблем, и, как вы можете видеть, пользовательский интерфейс разделен на две части. Сверху видна форма ввода. Используя поля ввода для Описание, Серьезность и Назначено, пользователь может вводить новые проблемы. Проблемы хранятся в локальном хранилище браузера. Список существующих проблем распечатан в нижней части. Здесь вы можете увидеть, что каждая проблема распечатана с подробным описанием, серьезностью и назначением. Кроме того, вы можете видеть, что проблема определяется уникальным идентификатором проблемы. Проблема - это GUID, который генерируется при создании проблемы и сохраняется в локальном хранилище.
Кроме того, каждой проблеме присвоен статус. По умолчанию статус - «Открыто». Если проблема решена, пользователь может установить статус «Закрыто» с помощью кнопки «Закрыть». Вопрос можно удалить из списка (и из локального хранилища), нажав кнопку «Удалить».

Настройка проекта

Настройка проекта очень проста. Поскольку мы хотим использовать только чистый JavaScript, нам не нужно устанавливать фреймворки или зависимости. Начните с создания новой папки проекта, а внутри этой новой папки создайте два новых пустых файла: index.html и main.js.

Файл index.html является точкой входа для нашего приложения и содержит HTML-код. Файл main.js будет включен в index.html и содержит соответствующий код JavaScript, который необходим для реализации примера приложения.

Создание index.html

Мы начинаем с создания базовой HTML-структуры в index.html, как вы можете видеть в следующем листинге:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>JS Issue Tracker</title>
  </head>
  <body>
    <script src="main.js"></script>
  </body>
</html>

включая JQuery, Bootstrap и Chance.js

Мы будем использовать классы CSS Bootstrap для применения стилей к компонентам пользовательского интерфейса. Самый простой способ включить Bootstrap - это добавить его из CDN.

Сначала добавьте следующее в раздел заголовка:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

Затем включите в основной раздел (прямо перед закрывающим тегом </body>) следующее:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

Мы собираемся использовать небольшую библиотеку JS (ChanceJS) для создания уникальных идентификаторов проблем. Включите эту библиотеку, добавив также следующую строку:

<script src="http://chancejs.com/chance.min.js"></script>

Использование live-сервера

В качестве веб-сервера разработки в этом руководстве мы используем live-server. live-server - небольшой веб-сервер с возможностью перезагрузки. Он доступен в виде пакета npm, поэтому установку можно выполнить с помощью:

$ npm install -g live-server

После завершения установки доступна команда live-server. Если вы выполните эту команду в каталоге проекта, запустится веб-сервер и наше приложение откроется в браузере.

Реализация пользовательского интерфейса

Давайте добавим HTML-код в index.html, который необходим для реализации пользовательского интерфейса:

<!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">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <title>JS Issue Tracker</title>
    <!-- Bootstrap -->
    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

  </head>
  <body onload="fetchIssues()">
    <div class="container">
      <h1>JS Issue Tracker <small>by CodingTheSmartWay.com</small></h1>
      <div class="jumbotron">
        <h3>Add New Issue:</h3>
        <form id="issueInputForm">
          <div class="form-group">
            <label for="issueDescInput">Description</label>
            <input type="text" class="form-control" id="issueDescInput" placeholder="Describe the issue ...">
          </div>
          <div class="form-group">
            <label for="issueDescInput">Severity</label>
             <select class="form-control" id="issueSeverityInput">
              <option value="Low">Low</option>
              <option value="Medium">Medium</option>
              <option value="High">High</option>
            </select> 
          </div>
          <div class="form-group">
            <label for="issueDescInput">Assigned To</label>
            <input type="text" class="form-control" id="issueAssignedToInput" placeholder="Enter responsible ...">
          </div>
          <button type="submit" class="btn btn-primary">Add</button>
        </form>
      </div>
      <div class="row">
        <div class="col-lg-12">
          <div id="issuesList">
          </div>
        </div>
      </div>
      <div class="footer">
        <p>&copy CodingTheSmartWay.com</p>
      </div>
    </div>
   
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="http://chancejs.com/chance.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
    <script src="main.js"></script>
  </body>
</html>

Сначала обратите внимание, что мы прикрепили обработчик события onload fetchIssues () к элементу <body>. Это гарантирует, что функция JavaScript fetchIssues () вызывается каждый раз при загрузке приложения. fetchIssues () будет реализован позже в файле main.js и будет загружать все проблемы из локального хранилища, генерирует вывод HTML для списка проблем и прикрепляет вывод к DOM.

Внутри основного раздела один элемент ‹div› с CSS-классом Bootstrap containe r используется для содержания всех остальных HTML-элементов.

Давайте посмотрим на реализацию формы. Важно отметить, что всем элементам ввода и самому элементу <form> присваивается идентификатор. Используя этот идентификатор, мы можем позже получить ссылку на этот элемент в коде JavaScript.

Кроме того, важно отметить, что HTML-код, необходимый для вывода списка существующих проблем, не включен в index.html. Причина очевидна. HTML-код, необходимый для вывода списка, является динамическим и зависит от записей о проблемах, полученных из локального хранилища. Итак, единственное, что вы можете найти здесь, - это элемент <div> с идентификатором issuesList. Этот элемент дает нам возможность сгенерировать необходимый HTML-код с помощью JavaScript, а затем поместить результат в этот элемент.

Получение данных о проблеме из локального хранилища

Давайте переключимся на main.js и приступим к реализации части JavaScript нашего приложения. Данные о выпуске должны быть сохранены в локальном хранилище браузера. Первое, что мы собираемся реализовать, - это код, необходимый для извлечения проблем из локального хранилища. Мы делаем это, добавляя функцию fetchIssues ():

function fetchIssues () {
  var issues = JSON.parse(localStorage.getItem('issues'));
  var issuesList = document.getElementById('issuesList');
  
  issuesList.innerHTML = '';
  
  for (var i = 0; i < issues.length; i++) {
    var id = issues[i].id;
    var desc = issues[i].description;
    var severity = issues[i].severity;
    var assignedTo = issues[i].assignedTo;
    var status = issues[i].status;
    
    issuesList.innerHTML +=   '<div class="well">'+
                              '<h6>Issue ID: ' + id + '</h6>'+
                              '<p><span class="label label-info">' + status + '</span></p>'+
                              '<h3>' + desc + '</h3>'+
                              '<p><span class="glyphicon glyphicon-time"></span> ' + severity + ' '+
                              '<span class="glyphicon glyphicon-user"></span> ' + assignedTo + '</p>'+
                              '<a href="#" class="btn btn-warning" onclick="setStatusClosed(\''+id+'\')">Close</a> '+
                              '<a href="#" class="btn btn-danger" onclick="deleteIssue(\''+id+'\')">Delete</a>'+
                              '</div>';
  }
}

Первая строка кода - это получение проблем из локального хранилища. Это делается путем выполнения localStorage.getItem('issues') и преобразования строкового результата в объект JSON.

Во второй строке кода мы получаем ссылку на элемент <div> с идентификатором issuesList. Доступ к HTML-содержимому этого элемента можно получить с помощью свойства innerHTML. Сначала мы используем это свойство, чтобы установить содержимое в пустую строку. Затем мы перебираем элементы в задачах, используя цикл for и добавляя вывод HTML для этого элемента в issuesList.innerHTML.

Сохранение данных о выпуске в локальном хранилище после отправки формы

Сначала нам нужно прикрепить обработчик событий к событию отправки формы. Это делается с помощью следующей строки кода:

document.getElementById('issueInputForm').addEventListener('submit', saveIssue);

Ссылка на элемент формы получается с помощью getElementById. Мы передаем строку issueInputForm, которая является идентификатором элемента <form>. Метод addEventListener вызывается для присоединения события отправки формы к функции обработчика событий saveIssue. Давайте теперь реализуем эту функцию:

function saveIssue(e) {
  var issueId = chance.guid();
  var issueDesc = document.getElementById('issueDescInput').value;
  var issueSeverity = document.getElementById('issueSeverityInput').value;
  var issueAssignedTo = document.getElementById('issueAssignedToInput').value;
  var issueStatus = 'Open';
  var issue = {
    id: issueId,
    description: issueDesc,
    severity: issueSeverity,
    assignedTo: issueAssignedTo,
    status: issueStatus
  }
  
  if (localStorage.getItem('issues') === null) {
    var issues = [];
    issues.push(issue);
    localStorage.setItem('issues', JSON.stringify(issues));
  } else {
    var issues = JSON.parse(localStorage.getItem('issues'));
    issues.push(issue);
    localStorage.setItem('issues', JSON.stringify(issues));
  }
  
  document.getElementById('issueInputForm').reset();
 
  fetchIssues();
  
  e.preventDefault(); 
}

Во-первых, входные значения из элементов управления формы извлекаются и сохраняются в локальных переменных. Для issueStatus задано значение Open, а issueId создается при вызове функции chance.guid (). Затем новый объект issue вставляется в объект issues в локальном хранилище.

Вставив объект issues в локальное хранилище, нам нужно очистить форму, вызвав метод reset (). Мы снова вызываем fetchIssues (), чтобы убедиться, что вывод списка сгенерирован повторно и что новый элемент задачи будет виден.

Наконец, нам нужно выполнить e.preventDefault (), чтобы избежать отправки формы по умолчанию.

Установка закрытого статуса

Вывод HTML, который создается для каждого элемента задачи в функции fetchIssues, содержит кнопку, с помощью которой можно установить статус задачи на Закрыто:

<a href="#" class="btn btn-warning" onclick="setStatusClosed(\''+id+'\')">Close</a>

Здесь мы присоединяем событие click к методу обработчика событий setStatusClosed. Реализация этого метода доступна в следующем листинге:

function setStatusClosed (id) {
  var issues = JSON.parse(localStorage.getItem('issues'));
  
  for(var i = 0; i < issues.length; i++) {
    if (issues[i].id == id) {
      issues[i].status = "Closed";
    }
  }
    
  localStorage.setItem('issues', JSON.stringify(issues));
  
  fetchIssues();
}

Идентификатор текущего элемента задачи передается в качестве параметра. Чтобы получить соответствующий элемент из локального хранилища, нам сначала нужно получить элементы задачи в формате JSON. Это делается путем вызова localStorage.getItem('issues') и передачи результата методу JSON.parse().

Удаление проблемы

Для каждого элемента задачи создается еще одна кнопка:

<a href="#" class="btn btn-danger" onclick="deleteIssue(\''+id+'\')">Delete</a>

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

function deleteIssue (id) {
  var issues = JSON.parse(localStorage.getItem('issues'));
  
  for(var i = 0; i < issues.length; i++) {
    if (issues[i].id == id) {
      issues.splice(i, 1);
    }
  }
  
  localStorage.setItem('issues', JSON.stringify(issues));
  
  fetchIssues();
}

Реализация аналогична реализации функции setStatusClosed, которую мы видели ранее. Основное отличие состоит в том, что мы используем метод splice для удаления текущего элемента из массива issues. После удаления текущего элемента проблемы из массива мы записываем его обратно в локальное хранилище и снова выполняем функцию fetchIssues, чтобы обновить вывод списка.

Резюме

Современные JavaScript-фреймворки, такие как Angular, React и Vue.js, позволяют легко и удобно писать одностраничные веб-приложения. Однако эти фреймворки не обязательны, и вы можете достичь тех же результатов с помощью простого и чистого JavaScript. Кроме того, понимание основ JavaScript поможет вам изучить и использовать JS-фреймворки.

В этом руководстве вы изучили основы JavaScript на практическом примере - демонстрации системы отслеживания проблем.

Видеоурок

Этот видеоурок содержит шаги, описанные в тексте выше:

Также ознакомьтесь с отличным Полный курс JavaScript: создание реального проекта

Это сообщение было впервые опубликовано на CodingTheSmartWay.com.