VGToast

Уведомления, стек, перетаскивание, AJAX и жизненный цикл.

AJAX и повторное открытие

Реальный GET endpoint демо: HTML, пустой ответ, ошибка и once.

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

HTML, пустой ответ и ошибка

Каждый запрос выполняется при новом открытии. Перед выбором следующего режима закройте тост. Обработка пустого ответа и ошибки показана в JavaScript.

Запрос ещё не отправлен.

Ожидание загрузки
HTML
<div id="toast-ajax-controls" class="d-flex flex-wrap gap-2">
  <button type="button" class="btn btn-primary btn-sm" data-mode="success">Загрузить HTML</button>
  <button type="button" class="btn btn-surface btn-sm" data-mode="empty">Пустой ответ</button>
  <button type="button" class="btn btn-surface btn-sm" data-mode="error">Ошибка 503</button>
</div>
<p id="toast-ajax-status" role="status" class="mt-3">Запрос ещё не отправлен.</p>
<div id="toast-ajax" class="vg-toast bottom center" role="status" aria-live="polite" >
  <div class="vg-toast-wrapper">
    <div class="vg-toast-content"><div class="vg-toast-body"><span id="toast-ajax-body">Ожидание загрузки</span></div></div>
    <div class="vg-toast-button"><button type="button" class="vg-btn-close" data-vg-dismiss="toast" aria-label="Закрыть уведомление"></button></div>
  </div>
</div>
JavaScript
/**
 * Описание: AJAX с явным target и состояниями ответа.
 * Возможности: рабочий пример публичного API VGToast.
 */
import { VGToast } from 'vgapp';

function initToastDemo() {
  const element = document.querySelector('#toast-ajax');
  if (!element) return;
  const status = document.querySelector('#toast-ajax-status');
  const target = document.querySelector('#toast-ajax-body');
  const instance = VGToast.getOrCreateInstance(element, {
    enableClickToast: false, animation: {enable: false, delay: 0},
    ajax: {route: '/api/toast/demo', target: '#toast-ajax-body', loader: true, once: false},
  });
  element.addEventListener('vg.toast.loaded', event => {
    const failed = event.detail.stats === 'error';
    if (failed) target.textContent = 'Не удалось загрузить уведомление. Повторите запрос.';
    else if (!target.textContent.trim()) target.textContent = 'Новых уведомлений нет.';
    status.textContent = failed ? 'Ошибка 503: можно повторить.' : 'Ответ получен: ' + event.detail.stats;
  });
  const controls = document.querySelector('#toast-ajax-controls');
  controls.addEventListener('click', event => {
    const button = event.target.closest('[data-mode]');
    if (!button) return;
    if (element.classList.contains('show')) {
      status.textContent = 'Сначала закройте открытое уведомление.';
      return;
    }
    button.setAttribute('data-ajax-route', '/api/toast/demo?mode=' + button.dataset.mode);
    status.textContent = 'Загрузка…';
    instance.show(button);
  });
}

initToastDemo();
CSS
/* Композиция демо и публичные переменные VGToast. Тему переключает OKAUX. */
.page-module-toast .vg-toast {
  --vg-toast-width: min(28rem, 100%);
  --vg-toast-border-radius: var(--vg-radius-lg);
  --vg-toast-background-color: var(--vg-bg-secondary);
  --vg-toast-color: var(--vg-text-primary);
  --vg-toast-border-color: var(--vg-border-default);
}
.page-module-toast .vg-toast-content { min-width: 0; overflow-wrap: anywhere; }
.module-toast-content { min-width: 0; }
.toast-demo-log { white-space: pre-wrap; overflow-wrap: anywhere; padding: 1rem; background: var(--vg-bg-secondary); border: 1px solid var(--vg-border-default); border-radius: var(--vg-radius-lg); }
.toast-demo-reference { overflow-wrap: anywhere; }
.toast-demo-reference dt { margin-top: 1rem; font-family: monospace; }
.toast-demo-reference dd { margin: .25rem 0 0; }

Загрузка один раз

Закройте тост и откройте снова: содержимое остаётся, счётчик загрузок не увеличивается. once отмечает завершение запроса, включая ошибочный; здесь endpoint всегда успешен.

Загрузок: 0

Ожидание
HTML
<button type="button" id="toast-once-trigger" class="btn btn-primary btn-sm">Открыть с загрузкой один раз</button>
<p id="toast-once-status" class="mt-3" role="status">Загрузок: 0</p>
<div id="toast-once" class="vg-toast bottom center" role="status" aria-live="polite" >
  <div class="vg-toast-wrapper">
    <div class="vg-toast-content"><div class="vg-toast-body"><span id="toast-once-body">Ожидание</span></div></div>
    <div class="vg-toast-button"><button type="button" class="vg-btn-close" data-vg-dismiss="toast" aria-label="Закрыть уведомление"></button></div>
  </div>
</div>
JavaScript
/**
 * Описание: повторное использование AJAX-контента.
 * Возможности: рабочий пример публичного API VGToast.
 */
import { VGToast } from 'vgapp';

function initToastDemo() {
  const element = document.querySelector('#toast-once');
  if (!element) return;
  let loads = 0;
  const instance = VGToast.getOrCreateInstance(element, {
    enableClickToast: false,
    ajax: {route: '/api/toast/demo', target: '#toast-once-body', loader: true, once: true},
  });
  element.addEventListener('vg.toast.loaded', () => {
    document.querySelector('#toast-once-status').textContent = 'Загрузок: ' + (++loads);
  });
  document.querySelector('#toast-once-trigger').addEventListener('click', () => instance.show());
}

initToastDemo();
CSS
/* Композиция демо и публичные переменные VGToast. Тему переключает OKAUX. */
.page-module-toast .vg-toast {
  --vg-toast-width: min(28rem, 100%);
  --vg-toast-border-radius: var(--vg-radius-lg);
  --vg-toast-background-color: var(--vg-bg-secondary);
  --vg-toast-color: var(--vg-text-primary);
  --vg-toast-border-color: var(--vg-border-default);
}
.page-module-toast .vg-toast-content { min-width: 0; overflow-wrap: anywhere; }
.module-toast-content { min-width: 0; }
.toast-demo-log { white-space: pre-wrap; overflow-wrap: anywhere; padding: 1rem; background: var(--vg-bg-secondary); border: 1px solid var(--vg-border-default); border-radius: var(--vg-radius-lg); }
.toast-demo-reference { overflow-wrap: anywhere; }
.toast-demo-reference dt { margin-top: 1rem; font-family: monospace; }
.toast-demo-reference dd { margin: .25rem 0 0; }