Инструкция для Web

DivKit для Web — это npm-пакет @divkitframework/divkit. Он отрисовывает JSON-верстку в DOM-элемент в браузере или в HTML-строку на сервере. Чтобы посмотреть, как выглядит верстка, без интеграции в проект, используйте DivKit Web Playground.

Подключение библиотеки и отрисовка первой карточки

Установка пакета

Установите пакет из npm:

npm i @divkitframework/divkit --save

В пакете несколько модулей, и каждый экспортирует функцию render. Выберите модуль в зависимости от того, где отрисовывается верстка:

Модуль Назначение
@divkitframework/divkit/client Отрисовка только в браузере.
@divkitframework/divkit/client-hydratable Отрисовка в браузере с гидратацией HTML, полученного с сервера. Размер модуля немного больше, чем у client.
@divkitframework/divkit/server Отрисовка в HTML-строку на сервере.

Модули поставляются в форматах ES-модулей и CommonJS: Node.js и сборщики сами выбирают подходящий. Описания типов TypeScript входят в пакет.

Подключение стилей

При любом способе подключения нужен файл стилей dist/client.css. Подключить его можно любым способом. Например, импортируйте файл как модуль, если ваш сборщик обрабатывает CSS:

import '@divkitframework/divkit/dist/client.css';

Или добавьте ссылку на файл в HTML-страницу:

<link rel="stylesheet" href="node_modules/@divkitframework/divkit/dist/client.css">

Отрисовка на клиенте

Добавьте на страницу элемент, в который будет отрисована карточка:

<div id="root"></div>

Вызовите функцию render из модуля client. Передайте в нее идентификатор блока, целевой элемент и JSON с версткой. Для примера выведем на экран небольшой текст:

import { render } from '@divkitframework/divkit/client';
import '@divkitframework/divkit/dist/client.css';

const json = {
    card: {
        log_id: 'text',
        states: [
            {
                state_id: 0,
                div: {
                    type: 'text',
                    text: 'Hello, DivKit!'
                }
            }
        ]
    }
};

const instance = render({
    id: 'hello',
    target: document.querySelector('#root'),
    json,
    onError(details) {
        console.error(details.error);
    }
});

Если все сделано без ошибок, на странице появится надпись «Hello, DivKit!». Функция возвращает экземпляр карточки, с помощью которого ее можно обновить или удалить.

Серверная отрисовка и гидратация

На сервере используйте модуль server. Его функция render не принимает параметр target и возвращает HTML-строку:

import { render } from '@divkitframework/divkit/server';

const html = render({
    id: 'hello',
    json,
    onError(details) {
        console.error(details.error);
    }
});

Вставьте полученную строку в элемент-контейнер и подключите к странице файл dist/client.css. Чтобы карточка стала интерактивной, в браузере вызовите render из модуля client-hydratable с параметром hydrate: true:

import { render } from '@divkitframework/divkit/client-hydratable';

render({
    id: 'hello',
    target: document.querySelector('#root'),
    hydrate: true,
    json,
    onError(details) {
        console.error(details.error);
    }
});

Примечание

Передавайте на сервере и на клиенте одинаковые id и json. По значению id генерируются идентификаторы и классы в разметке.

Готовый пример серверной отрисовки с гидратацией доступен на GitHub.

Подключение без сборки

Библиотеку можно подключить в браузере и без сборщика, но для рабочих проектов рекомендуется сборка.

Импортируйте функцию render из файла dist/esm/client.mjs:

<link rel="stylesheet" href="./node_modules/@divkitframework/divkit/dist/client.css">

<div id="root"></div>

<script type="module">
    import { render } from './node_modules/@divkitframework/divkit/dist/esm/client.mjs';

    render({
        id: 'hello',
        target: document.querySelector('#root'),
        json: {
            card: {
                log_id: 'text',
                states: [
                    {
                        state_id: 0,
                        div: {
                            type: 'text',
                            text: 'Hello, DivKit!'
                        }
                    }
                ]
            }
        }
    });
</script>

Скрипт dist/browser/client.js добавляет функцию render в глобальный объект window.Ya.DivKit:

<link rel="stylesheet" href="./node_modules/@divkitframework/divkit/dist/client.css">

<div id="root"></div>

<script src="./node_modules/@divkitframework/divkit/dist/browser/client.js"></script>
<script>
    window.Ya.DivKit.render({
        id: 'hello',
        target: document.querySelector('#root'),
        json: {
            card: {
                log_id: 'text',
                states: [
                    {
                        state_id: 0,
                        div: {
                            type: 'text',
                            text: 'Hello, DivKit!'
                        }
                    }
                ]
            }
        }
    });
</script>

Написание Ya.Divkit считается устаревшим — используйте Ya.DivKit.

React

Для React есть отдельный пакет @divkitframework/react. Его компонент DivKit принимает параметры функции render в виде пропсов.

Параметры функции render

Параметры id и json обязательны во всех модулях, параметр target — в модулях client и client-hydratable. Остальные параметры необязательны. В таблице перечислены основные параметры, а полный список с описаниями приведен в README пакета.

Параметр Модули Описание
id Все string. Уникальный идентификатор блока. Используется для генерации идентификаторов и классов, поэтому на странице не должно быть двух блоков с одинаковым id.
json Все object. JSON с версткой: объект card и необязательный объект templates.
target client, client-hydratable HTMLElement. Элемент, в который отрисовывается карточка.
hydrate client-hydratable boolean. Укажите true, чтобы гидратировать HTML, который уже находится в target.
onError Все function. Обработчик ошибок и предупреждений. См. раздел Ошибки.
onStat client, client-hydratable function. Обработчик для логирования нажатий и показов. См. раздел Статистика.
onCustomAction client, client-hydratable function. Обработчик действий, которые DivKit не выполняет сам. См. раздел Кастомные действия.
builtinProtocols Все string[]. Значение по умолчанию: ['http', 'https', 'tel', 'mailto', 'intent']. Элементы с действием, протокол которого есть в списке, отрисовываются как ссылки <a>, и нажатия на них обрабатывает браузер.
platform Все string. Возможные значения: desktop, touch, auto. Значение по умолчанию: auto. Настраивает обработку событий мыши или касаний.
direction Все string. Возможные значения: ltr, rtl. Значение по умолчанию: ltr. Направление текста и верстки.
theme Все string. Возможные значения: system, light, dark. Значение по умолчанию: system. См. раздел Тематизация.
themeVariableName Все string. Имя переменной, в которой хранится текущая тема. См. раздел Тематизация.
globalVariablesController client, client-hydratable object. Контроллер внешних переменных. См. раздел Переменные.
typefaceProvider Все function. Возвращает значение CSS-свойства font-family для шрифта из верстки. См. раздел Шрифты.
customComponents Все Map. Описания кастомных компонентов. См. раздел Кастомные компоненты.
extensions client, client-hydratable Map. Расширения, которые подключаются в верстке по идентификатору. См. раздел Расширения.
extensionsForAllComponents client, client-hydratable array. Расширения, которые применяются ко всем элементам. См. раздел Расширения.
fetchInit client, client-hydratable object или function. Второй аргумент функции fetch для запросов, которые отправляют действия download и submit.
tooltipRoot client, client-hydratable HTMLElement. Элемент, в который добавляются тултипы и меню вместо target. Помогает избежать обрезания.
store Все object. Внешнее хранилище для хранимых значений. Хранилище реализует методы get и set; метод get должен быть синхронным.
videoPlayerProvider Все object. Провайдер собственного видеоплеера. На сервере содержит свойство template — строку или функцию, которая возвращает разметку плеера; на клиенте — функцию instance, которая создает экземпляр плеера.
mix Все string. Дополнительный CSS-класс корневого элемента.
customization Все object. CSS-классы для кнопок скролла в gallery и pager на десктопе, а также для всплывающего меню и его пунктов.

Обработка действий, статистики и ошибок

Кастомные действия

Чтобы сделать интерфейс интерактивным, добавьте обработку действий. Действия с протоколом div-action DivKit выполняет сам, а ссылки с протоколами из списка builtinProtocols открывает браузер. Остальные действия передаются в обработчик onCustomAction: это ссылки с другими протоколами и действия с "typed": {"type": "custom"}.

Для примера превратим текст в кнопку, при нажатии на которую появится уведомление. Добавьте элементу действие:

"actions": [
    {
        "log_id": "button_pressed",
        "url": "notification://show-toast?text=Hello%2C%20DivKit%21"
    }
]

Обработайте это действие в onCustomAction:

render({
    id: 'hello',
    target: document.querySelector('#root'),
    json,
    onCustomAction(action) {
        const [address, query = ''] = (action.url || '').split('?');

        if (address === 'notification://show-toast') {
            alert(new URLSearchParams(query).get('text'));
        }
    }
});

Так можно повлиять из JSON-верстки не только на состояние самой карточки, но и на все приложение. Данные действия с "typed": {"type": "custom"} передаются в поле action.payload. Подробнее — в разделе Кастомные действия.

Статистика

Обработчик onStat предназначен для логирования нажатий и показов. В поле details.action передается действие, а поле details.type принимает одно из значений:

  • click — нажатие на элемент с действием, а также любое действие, у которого нет собственного типа;
  • visible — показ элемента, для которого заданы visibility_actions;
  • disappear — исчезновение элемента, для которого заданы disappear_actions;
  • trigger — срабатывание триггера.
render({
    id: 'hello',
    target: document.querySelector('#root'),
    json,
    onStat(details) {
        console.log(details.type, details.action.log_id);
    }
});

Ошибки

В обработчик onError передаются ошибки и предупреждения, которые возникают при разборе и отрисовке верстки. У объекта details.error есть поле level со значением error или warn и необязательное поле additional с дополнительными данными. Если обработчик не задан, DivKit выводит сообщения в консоль.

render({
    id: 'hello',
    target: document.querySelector('#root'),
    json,
    onError(details) {
        const { level, message, additional } = details.error;

        console.log(level, message, additional);
    }
});

Тематизация

Параметр theme задает тему карточки: light, dark или system. Со значением system, которое используется по умолчанию, тема определяется по настройкам системы пользователя (медиавыражение prefers-color-scheme) и меняется вместе с ними. На сервере настройки системы недоступны, поэтому со значением system верстка отрисовывается в светлой теме.

Чтобы использовать текущую тему в верстке, укажите в параметре themeVariableName имя переменной. DivKit создаст строковую переменную с этим именем и будет записывать в нее значение light или dark. Используйте переменную в выражениях: при смене темы зависящие от нее свойства обновятся без перезагрузки страницы.

Примечание

Если параметр themeVariableName не передан, переменная не создается. Имя переменной не должно совпадать с именами переменных карточки и внешних переменных, иначе DivKit сообщит об ошибке Duplicate variable.

render({
    id: 'themed',
    target: document.querySelector('#root'),
    json,
    theme: 'system',
    themeVariableName: 'theme'
});
Посмотреть пример верстки
{
    "card": {
        "log_id": "themed_card",
        "states": [
            {
                "state_id": 0,
                "div": {
                    "type": "text",
                    "text": "Hello, DivKit!",
                    "text_color": "@{theme == 'dark' ? '#ffffff' : '#000000'}",
                    "background": [
                        {
                            "type": "solid",
                            "color": "@{theme == 'dark' ? '#000000' : '#ffffff'}"
                        }
                    ]
                }
            }
        ]
    }
}

Тему уже отрисованной карточки меняет метод экземпляра setTheme, например instance.setTheme('dark'). В описаниях типов пакета этот метод помечен как устаревший.

Переменные

Модули client и client-hydratable экспортируют функции для работы с внешними переменными. Функция createVariable создает переменную, а createGlobalVariablesController — контроллер, через который переменные становятся доступны в карточке. Чтобы несколько карточек использовали общие переменные, передайте один и тот же контроллер в каждый вызов render.

import {
    render,
    createVariable,
    createGlobalVariablesController
} from '@divkitframework/divkit/client';

const userName = createVariable('user_name', 'string', 'Guest');

const controller = createGlobalVariablesController();
controller.setVariable(userName);

render({
    id: 'hello',
    target: document.querySelector('#root'),
    json,
    globalVariablesController: controller
});

const unsubscribe = userName.subscribe(value => {
    console.log(value);
});

userName.setValue('Alice');

В верстке переменная доступна по имени, например @{user_name}. Методы переменной:

  • subscribe — вызывает обработчик с текущим значением и затем при каждом его изменении. Возвращает функцию для отписки.
  • setValue — записывает новое значение.
  • getValue — возвращает текущее значение.

Имена переменных в одном контроллере должны быть уникальными: при добавлении второй переменной с тем же именем метод setVariable выбрасывает исключение.

Расширение возможностей

Кастомные компоненты

Элемент custom отрисовывается с помощью пользовательских элементов HTML (Custom Elements). Передайте в параметре customComponents объект Map, в котором ключ — значение custom_type из верстки, а значение — описание компонента с именем тега в поле element:

import { render } from '@divkitframework/divkit/client';

class CustomCard extends HTMLElement {
    connectedCallback() {
        this.textContent = `Start: ${this.getAttribute('start')}`;
    }
}

customElements.define('custom-card', CustomCard);

render({
    id: 'custom',
    target: document.querySelector('#root'),
    json: {
        card: {
            log_id: 'custom_card',
            states: [
                {
                    state_id: 0,
                    div: {
                        type: 'custom',
                        custom_type: 'custom_card',
                        custom_props: {
                            start: 15
                        }
                    }
                }
            ]
        }
    },
    customComponents: new Map([
        ['custom_card', { element: 'custom-card' }]
    ])
});

Свойства из custom_props передаются компоненту в виде HTML-атрибутов. Кастомные компоненты поддерживаются и при серверной отрисовке: разметку компонента для сервера можно передать в поле template описания.

Примеры на GitHub:

Расширения

По умолчанию ни одно расширение не подключено. Чтобы включить расширение, передайте в параметре extensions объект Map: ключ — идентификатор расширения из поля extensions элемента, значение — класс расширения. Модули client и client-hydratable экспортируют готовые расширения SizeProvider и Gesture, а также функции lottieExtensionBuilder и markdownExtensionBuilder, которые создают расширения для Lottie и Markdown.

import { render, SizeProvider } from '@divkitframework/divkit/client';

render({
    id: 'hello',
    target: document.querySelector('#root'),
    json,
    extensions: new Map([
        ['size_provider', SizeProvider]
    ])
});

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

Подробнее о расширениях и параметре extensionsForAllComponents — в разделе Подключение.

Шрифты

Шрифты подключаются на странице средствами CSS. Чтобы сопоставить имя шрифта из параметра font_family с CSS-шрифтом, передайте функцию typefaceProvider. Она получает имя шрифта и необязательный объект с насыщенностью fontWeight и возвращает значение CSS-свойства font-family:

render({
    id: 'hello',
    target: document.querySelector('#root'),
    json,
    typefaceProvider(fontFamily, opts) {
        if (fontFamily === 'display') {
            return '"My Display Font", sans-serif';
        }

        return '';
    }
});

Подробнее — в разделе Шрифты.

Обновление и удаление карточки

Функция render из модулей client и client-hydratable возвращает экземпляр карточки. Его методы:

Метод Описание
execAction(action) Выполняет действие в карточке.
applyPatch(patch) Применяет патч. Возвращает true, если патч применен.
setData(json) Перерисовывает карточку по новому JSON. Метод экспериментальный: его логика и API могут измениться.
$destroy() Уничтожает экземпляр и удаляет карточку со страницы.
instance.execAction({
    log_id: 'reset_counter',
    url: 'div-action://set_variable?name=counter&value=0'
});

instance.$destroy();

Метод setData старается сохранить состояние карточки, например значения в полях ввода. Он не меняет существующие переменные и триггеры, а только создает новые переменные.

Требования к окружению

Поддерживаемые браузеры:

chrome >= 67
safari >= 14
firefox >= 68

Для отдельных возможностей нужны более новые браузеры. Например, параметр aspect элемента container требует поддержки CSS-свойства aspect-ratio.

Для серверной отрисовки:

Node.js >= 14

Целые числа DivKit хранит в типе BigInt, если платформа его поддерживает. Учитывайте, что JSON.parse и метод json() ответа fetch возвращают большие целые числа как number, поэтому значения больше 2^53 могут потерять точность еще до передачи в DivKit.

Примеры проектов

Готовые к запуску примеры доступны на GitHub:

  • js и ts — подключение со сборкой;
  • globals и globals-esm — подключение без сборки;
  • ssr и node-esm — серверная отрисовка;
  • divkit-react — React с серверной отрисовкой.

Узнать больше

Вы можете обсуждать интересующие вас темы в сообществе пользователей DivKit в Telegram: https://t.me/divkit_community_ru.

Репозиторий DivKit

Предыдущая
Следующая