15.7. Пример: создание оглавления

We use cookies. Read the Privacy and Cookie Policy

Пример 15.7 показывает, как динамически создавать оглавление документа. Он демонстрирует многие концепции работы с документом, описанные в разделах выше: выбор элементов, навигация по документу, установка атрибутов элементов, установка свойства innerHTML и создание новых узлов и вставку их в документ. Пример снабжен большим количеством комментариев, которые призваны облегчить понимание программного кода.

Пример 15.7. Автоматическое создание оглавления документа

/**

* TOC.js: создает оглавление документа.

*

* Этот модуль регистрирует анонимную функцию, которая вызывается

* автоматически по окончании загрузки документа. Эта функция сначала

* отыскивает элемент документа с атрибутом id="TOC". Если такой элемент

* отсутствует, функция создает его, помещая в начало документа.

*

* Затем функция отыскивает все элементы с <h1> по <h6>, интерпретируя их как

* заголовки разделов и создает оглавление внутри элемента ТОС. Функция добавляет

* номера разделов в каждый заголовок и обертывает заголовки именованными

* якорными элементами, благодаря чему оглавление может ссылаться на них.

* Якорным элементам даются имена, начинающиеся с приставки "ТОС", поэтому вам следует

* избегать использовать эту приставку в своей разметке HTML.

*

* Оформление элементов оглавления можно реализовать с помощью CSS. Все элементы имеют

* класс "TOCEntry". Кроме того, каждый элемент оглавления имеет класс, соответствующий

* уровню заголовка раздела. Для заголовков, оформленных тегом <h1>, создаются элементы

* оглавления с классом "TOCLevell",для заголовков <h2> - с классом "T0CLevel2" и т. д.

* Номера разделов, вставляемые в заголовки, получают класс "TOCSectNum".

*

* Этот модуль можно использовать с каскадными таблицами стилей, такими как:

*

* #Т0С { border: solid black 1рх; margin: Юрх; padding: Юрх; }

* .TOCEntry { font-family: sans-serif; }

* .TOCEntry a { text-decoration: none; }

* .TOCLevell { font-size: 16pt; font-weight: bold; }

* .T0CLevel2 { font-size: 12pt; margin-left: .5in; }

* .TOCSectNum:after { content: "; }

*

* Последнее определение генерирует двоеточие и пробел после номера раздела.

* Чтобы скрыть номера разделов, можно использовать следующий стиль:

*

* .TOCSectNum { display: none }

*

* Этот модуль использует вспомогательную функцию onLoad().

**/

onLoad(function() { // Анонимная функция, определяющая локальн. обл. видимости

// Отыскать контейнерный элемент для оглавления.

// Если такой элемент отсутствует, создать его в начале документа,

  var toc = document.getElementById("TOC");

  if (!toc) {

    toc = document.createElementC'div");

    toc.id = "TOC";

    document.body.insertBefore(toc, document.body.firstChild);

  }

  // Отыскать все элементы заголовков разделов

  var headings;

  if (document.querySelectorAll) // Возможно есть более простой путь?

    headings = document.querySelectorAll(”h1,h2,h3.h4, h5. h6”);

  else // Иначе отыскать заголовки более сложным способом

    headings = findHeadings(document.body, []);

  // Выполняет рекурсивный обход тела документа в поисках заголовков

  function findHeadings(root, sects) {

    for(var с = root.firstChild; c != null; c = c.nextSibling) {

      if (c.nodeType !== 1) continue;

      if (c.tagName.length == 2 && c.tagName.charAt(O) == "H")

        sects.push(c);

      else

        findHeadings(c, sects);

    }

    return sects;

  }

  // Инициализировать массив, хранящий номера разделов,

  var sectionNumbers = [0,0,0,0,0,0];

  // Выполнить цикл по найденным элементам заголовков.

  for(var h = 0; h < headings.length; h++) {

    var heading = headings[h];

    // Пропустить заголовки, находящиеся в контейнере оглавления,

    if (heading.parentNode == toc) continue;

    // Определить уровень заголовка.

    var level = parseInt(heading.tagName.charAt(1));

    if (isNaN(level) || level < 1 || level > 6) continue;

    // Увеличить номер раздела для этого уровня и установить

    // номера разделов более низкого уровня равными нулю.

    sectionNumbers[level-1]++;

    for(var і = level; і < 6; і++) sectionNumbers[i] = 0;

    // Объединить номера разделов всех уровней,

    // чтобы получился номер вида 2.3.1.

    var sectionNumber = sectionNumbers.slice(0,level).join(".")

    // Добавить номер раздела в заголовок. Номер помещается в элемент <span>,

    // чтобы его можно было стилизовать с помощью CSS.

    var span = document.createElement("span");

    span.className = "TOCSectNum";

    span.innerHTML = sectionNumber;

    heading.insertBefore(span, heading.firstChild);

    // Обернуть заголовок якорным элементом, чтобы можно было

    // сконструировать ссылку на него.

    var anchor = document.сreateElement("а");

    anchor.name = "TOC"+sectionNumber;

    heading.parentNode.insertBefore(anchor, heading);

    anchor.appendChild(heading);

    // Создать ссылку на этот раздел,

    var link = document.createElement("а");

    link.href = "#T0C" + sectionNumber; // Адрес назначения ссылки

    link.innerHTML = heading.innerHTML; // Текст ссылки совпадает

                                        // с текстом заголовка

    // Поместить ссылку в элемент div, чтобы обеспечить возможность

    // стилизации в зависимости от уровня.

    var entry = document.сreateElement("div");

    entry.className = "TOCEntry TOCLevel" + level;

    entry.appendChild(link);

    // И добавить элемент div в контейнер оглавления,

    toc.appendChild(entry);

  }

});