Рендеринг заголовков

В библиотеке Marked рендеринг заголовков осуществляется через механизм lexer → parser → renderer, где текст Markdown сначала анализируется, а затем преобразуется в HTML. Заголовки обозначаются символами # для уровней H1–H6 или через подчеркивание === и --- для H1 и H2 соответственно.

Определение уровня заголовка

Markdown позволяет задавать заголовки двумя способами:

  1. Atx-стиль — использование решеток:
# Заголовок первого уровня
## Заголовок второго уровня
###### Заголовок шестого уровня
  1. Setext-стиль — подчеркивание текстовой строки:
Заголовок первого уровня
=======================

Заголовок второго уровня
-----------------------

Marked корректно распознает оба стиля и передает информацию о тексте заголовка и уровне в renderer.

Настройка рендерера

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

const marked = require('marked');

const renderer = new marked.Renderer();

renderer.heading = function (text, level, raw, slugger) {
    const id = slugger.slug(raw);
    return `<h${level} id="${id}">${text}</h${level}>\n`;
};

marked.use({ renderer });

Параметры метода heading:

  • text — уже обработанный Markdown текст заголовка, готовый к вставке в HTML.
  • level — число от 1 до 6, соответствующее тегу <h1><h6>.
  • raw — исходный текст заголовка без обработки Markdown.
  • slugger — объект для генерации уникальных идентификаторов (id) на основе исходного текста.

Генерация уникальных идентификаторов

Для удобной навигации и ссылок на заголовки важно создавать уникальные id. Marked предоставляет класс Slugger, который автоматически предотвращает дублирование:

const slugger = new marked.Slugger();
const id1 = slugger.slug('Заголовок'); // "zagolovok"
const id2 = slugger.slug('Заголовок'); // "zagolovok-1"

В кастомном рендерере можно использовать этот объект для установки атрибутов id:

renderer.heading = function (text, level, raw) {
    const id = slugger.slug(raw);
    return `<h${level} id="${id}">${text}</h${level}>\n`;
};

Добавление классов и атрибутов

Для стилизации заголовков часто требуется добавить классы, data- атрибуты или иконки:

renderer.heading = function (text, level, raw) {
    const id = slugger.slug(raw);
    const classes = `heading level-${level}`;
    return `<h${level} id="${id}" class="${classes}">${text}</h${level}>\n`;
};

Можно динамически изменять стили в зависимости от уровня или содержимого текста.

Применение токенов для анализа заголовков

Перед рендерингом можно использовать lexer, чтобы получить подробную информацию о заголовках:

const tokens = marked.lexer(`
# Главный заголовок
## Подзаголовок
`);
tokens.forEach(token => {
    if (token.type === 'heading') {
        console.log(token.depth, token.text);
    }
});

Токены содержат:

  • type — тип элемента (heading для заголовков).
  • depth — уровень заголовка.
  • text — текст заголовка без Markdown разметки.
  • tokens — массив внутренних токенов, если внутри заголовка есть форматирование (курсив, ссылки и т.п.).

Интеграция с другими функциями

Рендеринг заголовков можно комбинировать с таблицей содержимого (TOC) или анкорными ссылками, используя slugger и кастомный renderer:

const toc = [];

renderer.heading = function (text, level, raw) {
    const id = slugger.slug(raw);
    toc.push({ level, text, id });
    return `<h${level} id="${id}">${text}</h${level}>\n`;
};

После рендеринга Markdown можно использовать массив toc для генерации списка навигации.

Обработка внутренних элементов

Marked поддерживает вложенные элементы внутри заголовков, такие как курсив, жирный текст и ссылки. При рендеринге текст заголовка уже проходит через парсер, и кастомный метод heading получает готовый HTML для вставки.

const md = '# **Важный** заголовок';
marked(md, { renderer });

В text уже будет: <strong>Важный</strong> заголовок.

Оптимизация производительности

Для больших документов рекомендуется:

  • Переиспользовать один экземпляр Slugger, чтобы избежать лишних аллокаций.
  • Кэшировать результаты парсинга, если заголовки часто повторяются.
  • Минимизировать сложные вычисления внутри кастомного renderer.heading.

Эти методы обеспечивают гибкую и расширяемую работу с заголовками в Marked, позволяя создавать структурированные, уникальные и стилизованные HTML-документы на основе Markdown.