Книга: Выразительный JavaScript

Показ тем

Показ тем

Чтобы иметь возможность обновлять список тем при поступлении изменений, клиент должен отслеживать темы, которые он показывает сейчас. Тогда, если поступает новая версия темы, которая уже есть на экране, её можно заменить прямо на месте обновлённой версией. Сходным образом, когда поступает информация об удалении темы, нужный элемент DOM можно удалить из документа.

Функция displayTalks используется как для построения начального экрана, так и для его обновления при изменениях. Она будет использовать объект shownTalks, связывающий заголовки тем с узлами DOM, чтобы запомнить темы, которые уже есть на экране.

var talkDiv = document.querySelector("#talks");
var shownTalks = Object.create(null);
function displayTalks(talks) {
  talks.forEach(function(talk) {
    var shown = shownTalks[talk.title];
    if (talk.deleted) {
      if (shown) {
        talkDiv.removeChild(shown);
        delete shownTalks[talk.title];
      }
    } else {
      var node = drawTalk(talk);
      if (shown)
        talkDiv.replaceChild(node, shown);
      else
        talkDiv.appendChild(node);
      shownTalks[talk.title] = node;
    }
  });
}

Структура DOM для тем строится по шаблону, включённому в HTML документ. Сначала нужно определить instantiateTemplate, который находит и заполняет шаблон.

Параметр name – имя шаблона. Чтобы найти элемент шаблона, мы ищем элементы, у которых имя класса совпадает с именем шаблона, который является дочерним у элемента с ID “template”. Метод querySelector облегчает этот процесс. На странице есть шаблоны “talk” и “comment”.

function instantiateTemplate(name, values) {
  function instantiateText(text) {
    return text.replace(/{{(w+)}}/g, function(_, name) {
      return values[name];
    });
  }
  function instantiate(node) {
    if (node.nodeType == document.ELEMENT_NODE) {
      var copy = node.cloneNode();
      for (var i = 0; i < node.childNodes.length; i++)
        copy.appendChild(instantiate(node.childNodes[i]));
      return copy;
    } else if (node.nodeType == document.TEXT_NODE) {
      return document.createTextNode(
               instantiateText(node.nodeValue));
    }
  }
  var template = document.querySelector("#template ." + name);
  return instantiate(template);
}

Метод cloneNode, который есть у всех узлов DOM, создаёт копию узла. Он не скопирует дочерние узлы, если не передать ему первым аргументом true. Функция instantiate рекурсивно создаёт копию шаблона, заполняя его по ходу дела.

Второй аргумент instantiateTemplate должен быть объектом, чьи свойства содержат строки, которые надо ввести в шаблон. Метка вроде будет заменена значением свойства “title”.

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

function drawTalk(talk) {
  var node = instantiateTemplate("talk", talk);
  var comments = node.querySelector(".comments");
  talk.comments.forEach(function(comment) {
    comments.appendChild(
      instantiateTemplate("comment", comment));
  });
  node.querySelector("button.del").addEventListener(
    "click", deleteTalk.bind(null, talk.title));
  var form = node.querySelector("form");
  form.addEventListener("submit", function(event) {
    event.preventDefault();
    addComment(talk.title, form.elements.comment.value);
    form.reset();
  });
  return node;
}

После завершения обработки шаблона “talk” нужно много чего подлатать. Во-первых, нужно вывести комментарии, путём многократного добавления шаблона "comment" и добавления результатов к узлу класса "comments". Затем, обработчики событий нужно присоединить к кнопке, которая удаляет задачу и к форме, добавляющей комментарий.

Оглавление книги


Генерация: 0.525. Запросов К БД/Cache: 2 / 0
поделиться
Вверх Вниз