VGTabs

Переключение панелей, клавиатура, индикатор и удалённый контент.

API и события

Ручная инициализация, отмена перехода, жизненный цикл и справочник.

Каждый пример независим. Кнопка «Показать код» раскрывает HTML, JavaScript и CSS, которые используются в самом примере. Стили оболочки и кнопок предоставляет OKAUX 1.0.2.

Методы, события и отмена перехода

Включите запрет и попробуйте открыть настройки. Затем освободите экземпляры и создайте их повторно.

Кнопки выше используют публичные методы VGTabs.
Настройки открыты. События ниже показывают предыдущую и следующую вкладки.

Экземпляры готовы.

Ожидание действий
HTML
<div class="tabs-demo-toolbar">
  <button type="button" class="btn btn-surface btn-sm" id="tabs-api-open">Открыть настройки</button>
  <button type="button" class="btn btn-surface btn-sm" id="tabs-api-dispose">Освободить экземпляры</button>
  <button type="button" class="btn btn-surface btn-sm" id="tabs-api-init">Инициализировать</button>
  <label><input type="checkbox" id="tabs-api-lock"> Запретить переход в настройки</label>
</div>
<div class="tabs-demo" id="tabs-api-demo">
  <div class="vg-tabs">
    <div class="vg-tabs-panel" role="tablist" aria-label="Разделы примера">
      <div class="vg-tabs-item"><button type="button" class="vg-tabs-link active" id="tabs-api-0-tab" data-vg-toggle="tab" data-vg-target="#tabs-api-0" aria-controls="tabs-api-0">Обзор</button></div>
      <div class="vg-tabs-item"><button type="button" class="vg-tabs-link" id="tabs-api-1-tab" data-vg-toggle="tab" data-vg-target="#tabs-api-1" aria-controls="tabs-api-1">Настройки</button></div>
    </div>
  </div>
  <div class="vg-tabs-content tabs-demo-content">
    <div class="vg-tabs-pane show active" id="tabs-api-0" tabindex="0">Кнопки выше используют публичные методы VGTabs.</div>
    <div class="vg-tabs-pane" id="tabs-api-1" tabindex="0">Настройки открыты. События ниже показывают предыдущую и следующую вкладки.</div>
  </div>
</div>
<p id="tabs-api-status" role="status">Экземпляры готовы.</p>
<pre class="tabs-demo-log" id="tabs-api-log" aria-label="Журнал событий" aria-live="polite">Ожидание действий</pre>
JavaScript
/**
 * Описание: публичное управление VGTabs.
 * Возможности: инициализация, show, dispose, отмена перехода и журнал событий.
 */
import { VGTabs } from 'vgapp';

function initTabsDemo() {
  const root = document.querySelector('#tabs-api-demo');
  if (!root || root.dataset.ready) return;
  root.dataset.ready = 'true';
  const tabs = [...root.querySelectorAll('[data-vg-toggle="tab"]')];
  const status = document.querySelector('#tabs-api-status');
  const log = document.querySelector('#tabs-api-log');
  const entries = [];
  const init = () => {
    tabs.forEach(tab => VGTabs.getOrCreateInstance(tab, { slide: true }));
    status.textContent = 'Экземпляры готовы: ' + tabs.filter(tab => VGTabs.getInstance(tab)).length;
  };
  for (const name of ['hide', 'show', 'hidden', 'shown']) {
    root.addEventListener('vg.tabs.' + name, event => {
      if (name === 'show' && event.target === tabs[1] && document.querySelector('#tabs-api-lock').checked) {
        event.preventDefault();
      }
      entries.unshift(name + ': ' + event.target.textContent.trim() +
        ' ← relatedTarget: ' + (event.relatedTarget?.textContent.trim() || 'нет') +
        (event.defaultPrevented ? ' [отменено]' : ''));
      log.textContent = entries.slice(0, 8).join('\n');
    });
  }
  document.querySelector('#tabs-api-open').addEventListener('click', () => {
    VGTabs.getOrCreateInstance(tabs[1], { slide: true }).show();
  });
  document.querySelector('#tabs-api-dispose').addEventListener('click', () => {
    tabs.forEach(tab => VGTabs.getInstance(tab)?.dispose());
    status.textContent = 'Экземпляры освобождены. Data API остаётся подключён: клик создаст экземпляр заново.';
  });
  document.querySelector('#tabs-api-init').addEventListener('click', init);
  init();
}

initTabsDemo();
CSS
/* Токены OKAUX в демо настроены с префиксом vg; состояние темы общее. */
.tabs-demo { min-width: 0; }
.tabs-demo-content {
  margin-top: 1rem;
  padding: 1rem;
  border: 1px solid var(--vg-border-default);
  border-radius: var(--vg-radius-md);
  background: var(--vg-bg-secondary);
  overflow-wrap: anywhere;
}
.tabs-demo-custom {
  --vg-tabs-panel-gap: 0.35rem;
  --vg-tabs-link-padding-x: 0.75rem;
  --vg-tabs-slider-border-radius: 999px;
  --vg-tabs-track-slider-border-radius: 999px;
}
.tabs-demo-vertical {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  align-items: start;
  gap: 1rem;
}
.tabs-demo-vertical > .tabs-demo-content { margin-top: 0; }
@media (max-width: 575.98px) {
  .tabs-demo-vertical { grid-template-columns: minmax(0, 1fr); }
}
.tabs-demo-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; margin-bottom: 1rem; }
.tabs-demo-status { margin-top: 1rem; }
.tabs-demo-log { max-width: 100%; white-space: pre-wrap; overflow-wrap: anywhere; font-size: 0.85rem; }

Подключение и Data API

import { VGTabs } from 'vgapp'; стили: vgapp/scss либо отдельный Sass entrypoint vgapp/tabs с общими стилями vgapp/default. В браузерной сборке класс доступен как vgapp.VGTabs.

Экземпляр принадлежит кнопке, а не контейнеру. При загрузке создаются экземпляры активных [data-vg-toggle="tab"]; остальные создаются при клике или переходе с клавиатуры. Для динамически добавленной группы вручную вызовите getOrCreateInstance на активной кнопке.

Порядок настроек: значения по умолчанию → JavaScript → атрибуты .vg-tabs → атрибуты кнопки. Используйте data-slide, data-hash, data-ajax-route или JSON в data-params. Атрибут data-vg-tabs не является конфигурацией модуля.

Параметры

slide: false / hash: false
Индикатор и выбор начальной панели по URL. Hash читается только при инициализации; URL при show() не изменяется.
ajax.route: '' / ajax.target: ''
URL и CSS-селектор контейнера для доверенного HTML. Первая активная панель сама запрос не запускает: загрузка происходит при переходе на вкладку.
ajax.method: 'get' / ajax.data: {}
Поддерживаются get, post, delete. Для GET данные становятся query-параметрами; для POST передаются в теле.
ajax.once: true
Повторный успешный запрос пропускается в течение жизни экземпляра; ошибка не кэшируется. false загружает при каждом повторном открытии, но не по клику на уже активную вкладку.
ajax.loader: false / ajax.timeout: 0
Встроенный vg-loader в целевом контейнере и задержка до отправки в миллисекундах (не таймаут сети). Загрузчик требует output=true.
ajax.output: true
Автоматическая вставка HTML. Для JSON задавайте false и обрабатывайте event.data.response. Пустой ответ и сообщение об ошибке оформляет приложение.

Методы

new VGTabs(element, options)
Создаёт экземпляр одной кнопки. Не вызывайте повторно для уже инициализированного элемента.
VGTabs.getInstance(element)
Возвращает экземпляр либо null.
VGTabs.getOrCreateInstance(element, options)
Переиспользует существующий экземпляр. Новые options не обновляют уже созданный.
instance.show()
Активирует панель. Повторный вызов для активной или disabled-вкладки ничего не делает.
instance.dispose()
Освобождает экземпляр, обработчики и наблюдение за индикатором. DOM и активное состояние сохраняются; делегированный Data API не отключается.

События

Для обычных кнопок: hide → show → hidden → shown. Отмените hide или show через preventDefault(), чтобы сохранить текущую вкладку. События всплывают от кнопки. При анимации завершение панели может произойти позже shown.

vg.tabs.hide / vg.tabs.hidden
event.target — старая кнопка; relatedTarget — новая.
vg.tabs.show / vg.tabs.shown
event.target — новая кнопка; relatedTarget — старая, либо null.
vg.tabs.loaded
После каждого выполненного запроса: event.stats (именно stats) — success или error; event.data содержит code и response. Событие shown не означает, что AJAX уже завершён.

CSS-переменные

Префикс всех переменных ниже — --vg-tabs-. Задавайте их на своей .vg-tabs. Тема общая с OKAUX через data-theme и адаптер vgapp/theme.

panel-gap; link-padding-x / link-padding-y
Расстояние между кнопками и их внутренние отступы.
link-color / link-bg / link-border-color
Обычное состояние.
link-active-color / link-active-bg / link-border-active-color
Активная вкладка.
link-focus-color / link-focus-bg / link-border-focus-color
Состояние фокуса.
link-disabled-color / link-disabled-bg / link-border-disabled-color
Отключённая кнопка с disabled.
link-border-width / link-border-style / link-border-radius / link-transition
Рамка, скругление и переходы кнопок.
slider-bg / slider-link-color / slider-border-radius / slider-transition
Индикатор и текст кнопки над ним.
track-slider-padding-x / track-slider-padding-y / track-slider-border-radius / track-slider-bg
Подложка индикатора.

panel-margin-bottom объявлена в карте переменных, но текущим SCSS не применяется: расстояние до контента задаёт композиция примера. Встроенной загрузки «по клику на активную вкладку», live hash-router и отдельного метода reload нет.

Кнопки внутри выпадающего меню требуют отдельного компонента меню. VGTabs сам меню не открывает; его старые селекторы .dropdown / .dropdown-content не заменяют контракт VGDropdown.