Всплывающие сообщения для сайта на чистом JavaScript

Александр Мальцев
Александр Мальцев
21K
8
Всплывающие сообщения для сайта на чистом JavaScript
Содержание:
  1. Исходные коды
  2. Подключение и использование
  3. Подробное описание
  4. Комментарии

Статья, в которой рассмотрим, как можно самостоятельно создать для сайта всплывающие сообщения (уведомления) подобно тому, как это выполняет jGrowl (плагин для jQuery).

Исходные коды

Всплывающие сообщения – это ненавязчивый способ показа сообщений для пользователя. Они позволяют отображать уведомления пользователю заметным образом и не мешая при этом его взаимодействию с сайтом или веб-приложением.

Проект, рассматриваемый в рамках этой статьи, расположен на Github по адресу: https://github.com/itchief/ui-components/tree/master/toast

Он написан на чистом JavaScript без использования сторонних библиотек.

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

Всплывающие уведомления для сайта на чистом JavaScript

Демо

Подключение и использование

Компонент для показа всплывающих уведомлений состоит из 2 файлов: «toast.css» и «toast.js». Преимуществом данной библиотеки состоит в том, что она имеет очень маленький размер («toast.min.js» немного больше 1Кбайта). В отличие от библиотеки jGrowl эти сообщения не требуют библиотеку jQuery, что для многих сайтов очень важно.

Подключение компонента осуществляется посредством:

<link href="path/to/toast.min.css" rel="stylesheet">
<script src="path/to/toast.min.js"></script>

Вывод всплывающего сообщения на страницу осуществляется посредством создания экземпляра объекта Toast:

/*
  title - название заголовка
  text - текст сообщения
  theme - тема
  autohide - нужно ли автоматически скрыть всплывающее сообщение через interval миллисекунд
  interval - количество миллисекунд через которые необходимо скрыть сообщение
*/
new Toast({
  title: 'Заголовок',
  text: 'Сообщение...',
  theme: 'light',
  autohide: true,
  interval: 10000
});

Если нужно создать сообщение без заголовка, то нужно просто ключу title установить значение false:

// без заголовка
new Toast({
  title: false,
  text: 'Сообщение...',
  theme: 'light',
  autohide: true,
  interval: 10000
});

Подробное описание

Создание HTML кода всплывающих сообщений как с заголовком, так и без него выполняется в JavaScript. Целью является создание следующей структуры:

<!-- без заголовка -->
<div class="toast toast_message toast_default">
  <div class="toast__body">Сообщение...</div>
  <button class="toast__close" type="button"></button>
</div>

<!-- с заголовком -->
<div class="toast toast_default">
  <div class="toast__header">Заголовок</div>
  <div class="toast__body">Сообщение...</div>
  <button class="toast__close" type="button"></button>
</div>

HTML код сообщений простой. Он состоит из элемента с классом toast, в котором в зависимости от типа уведомления расположены два или три элемента:

  • <div> с классом toast__header - заголовок;
  • <div> с классом toast__body - элемент, в котором выводится само сообщение;
  • <button> с классом toast__close - кнопка, для закрытия сообщения.

С помощью классов в CSS добавляются стили к этим элементам:

/* CSS-переменные */
:root {
  --toast-border-radius: 0.25rem;
  --toast-theme-default: #fff;
}

.toast {
  font-size: 0.875rem;
  background-clip: padding-box;
  border: 1px solid rgba(0, 0, 0, 0.05);
  border-radius: var(--toast-border-radius);
  box-shadow: 0 .125rem .25rem rgba(0, 0, 0, 0.075);
  display: none;
  position: relative;
  overflow: hidden;
}

.toast_default {
  color: #212529;
  background-color: var(--toast-theme-default);
}

.toast:not(:last-child) {
  margin-bottom: 0.75rem;
}

.toast__header {
  position: relative;
  padding: 0.5rem 2.25rem 0.5rem 1rem;
  background-color: rgba(0, 0, 0, 0.03);
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}

.toast__close {
  content: "";
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  width: 0.875em;
  height: 0.875em;
  background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/0.875em auto no-repeat;
  border: 0;
  opacity: 0.5;
  cursor: pointer;
  transition: opacity 0.1s ease-in-out;
}

.toast__close:hover {
  opacity: 1;
}

.toast__body {
  padding: 1rem;
}

.toast_message .toast__body {
  padding-right: 2.25rem;
}

Класс toast__close ещё используется в обработчике события click. При нажатию на эту кнопку выполняется закрытие сообщения.

this._el.addEventListener('click', (e) => {
  if (e.target.classList.contains('toast__close')) {
    // вызываем метод, скрывающий сообщение
    this._hide();
  }
});

После того как JavaScript добавляет HTML код всплывающего сообщения на страницу, оно не отображается, т.к. по умолчанию оно имеет display: none. Его показ осуществляется после того, как к нему добавляется класс toast_show.

.toast_show {
  display: block;
}

Скрытие сообщения выполняется путём удаления класса toast_show.

Задание темы осуществляется посредством добавления класса.

Например, тема primary устанавливается так:

<div class="toast toast_primary">...</div>

Помещение элементов .toast выполняется в контейнер .toast-container. Его создание тоже осуществляется с помощью JavaScript, но только в том случае, если его нет на странице.

if (!document.querySelector('.toast-container')) {
  const container = document.createElement('div');
  container.classList.add('toast-container');
  document.body.append(container);
}

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

:root {
  --toast-width: 270px;
}

.toast-container {
  position: fixed;
  top: 15px;
  right: 15px;
  width: var(--toast-width);
}

Написан код JavaScript в виде класса и имеет следующую структуру:

class Toast {
  constructor(params) { ... }
  _show() { ... }
  _hide() { ... }
  _create() { ... }
}

Комментарии:

  1. pumble
    pumble
    14.01.2022, 04:36
    Здравствуйте! Очень хороший пример, хоче внедрить его на свой сайт. Но к сожалению, у меня не получается. Если использую Ваш код в целости то все работает, но как только хочу оставить саму кнопку и удаляю лишнее, скрипт перестает работать (в таком виде):
    
    
                  <!DOCTYPE html>
    <html lang="ru">
    
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
      <title>Toast на чистом JavaScript - Пример 02</title>
      <style>
        body {
          margin: 0;
          font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
          font-size: 1rem;
          font-weight: 400;
          line-height: 1.5;
          color: #212529;
          text-align: left;
          background-color: #fff;
        }
    
        *,
        *::before,
        *::after {
          box-sizing: border-box;
        }
      </style>
      <link href="toast.min.css" rel="stylesheet">
      <script src="toast.min.js"></script>
    </head>
    
    <body style="min-height: 100vh;">
    
          <button id="add-toast" type="button" style="width: 100%;">Добавить toast</button>
        </div>
      </div>
    
      <script>
        document.querySelector('[name="toast-without-title"]').onchange = (e) => {
          document.querySelector('[name="toast-title"]').disabled = e.target.checked;
        }
    
        document.addEventListener('hide.toast', (e) => {
          console.log(e.detail.target);
        });
    
        document.querySelector('#add-toast').onclick = () => {
          /*
            title - название заголовка
            text - текст сообщения
            theme - тема
            autohide - нужно ли автоматически скрыть всплывающее сообщение через interval миллисекунд interval - количество миллисекунд через которые необходимо скрыть сообщение
          */
          new Toast({
      title: false,
      text: 'Gotowe...',
      theme: 'danger',
      autohide: true,
      interval: 10000
    });
        }
      </script>
    
    </body>
    
    </html>
    
    Подскажите, пожалуйста, что я делаю не так и как внедрить это на своем сайте?
    1. pumble
      pumble
      14.01.2022, 14:24
      Вопрос закрыт :)
    2. Sergby
      Sergby
      05.12.2021, 21:16
      Привет. Очень круто все расписано и классные примеры. Но я так и не понял как заставить работать это на моем сайте.
      Статьи расписаны легко и приятны для чтения. Спасибо Вам)
      1. Александр Мальцев
        Александр Мальцев
        06.12.2021, 14:28
        Привет! Просто подключаете «toast.min.css» и «toast.min.js» к странице. После этого в нужных местах своего скрипта, когда нужно вывести какую-то информацию пользователю (например, при добавлении товара в корзину), показываете всплывающее сообщение:
        new Toast({
          title: false,
          text: 'Такой-то товар добавлен в корзину...',
          theme: 'light',
          autohide: false
        });
      2. Олег
        Олег
        24.09.2021, 08:14
        Добрый день Александр! Пример очень хороший, именно такой искал для оповещений посетителям сайта. Единственное меня беспокоит о назойливостью, т.е. если посетитель будет переходить с одной странице сайта на другой то модальное окно будет постоянно появляться. Скажите пожалуйста, можно ли добавить временный таймер чтоб окно к примеру появлялось через 2 или 3 часа или может через 20 переходов страниц?
        1. Александр Мальцев
          Александр Мальцев
          06.10.2021, 13:14
          Привет! Для этого можно использовать LocalStorage.
          window.addEventListener('load', (e) => {
            const showToast = () => {
              localStorage.setItem('toast-time', Date.now());
              new Toast({
                title: 'Заголовок',
                text: 'Сообщение...',
                theme: 'warning',
                autohide: false
              });
            }
            const time = localStorage.getItem('toast-time');
            if (time) {
              // если прошло больше 3 часов
              if (Date.now() > time + 1000 * 60 * 60 * 3) {
                showToast();
              }
            } else {
              showToast();
            }
          });
          В этом коде после загрузки получаем значение по ключу toast-time, содержащее время последнего показа сообщения. Если его нет, или прошло уже три часа, то показываем сообщение и записываем новое значение времени в LocalStorage. Если нужно через 20 переходов, то аналогично.
        2. Gio
          Gio
          20.09.2021, 02:50
          Здравствуйте. Скажите, пожалуйста. Как я могу сделать так, чтобы уведомление получил отдельный пользователь? то есть: я создал интернет магазин и я хочу чтобы в браузере у заказчика выплыло уведомление о готовности товара и прочее. возможно ли это как то? заранее благодарю за ответ
          1. Владимир
            Владимир
            24.06.2021, 18:52
            Подскажите, пожалуйста, как сделать чтобы просто можно было прописать код всплывающего окна и оно всплывало когда открывается страница сайта?
            1. Александр Мальцев
              Александр Мальцев
              27.06.2021, 09:30
              Вот пример окна, появляющегося после загрузки страницы: modal-02
            2. Александр Мальцев
              Александр Мальцев
              07.12.2019, 11:01
              Добрый день!
              Добавить звуковое оповещение можно так:
              // создаем аудио объект
              var snd = new Audio('toast.wav');
              ...
              // добавляем проигрывание его в метод add
              Toast.add = function (params) {
                ...
                snd.currentTime = 0;
                snd.play();
                return toast;
              });
              Пример со звуком можно посмотреть здесь.
              1. Алексей
                Алексей
                07.12.2019, 11:09
                Большое спасибо. А можете ещё подсказать, как добавить в тело сообщения ссылку
                1. Александр Мальцев
                  Александр Мальцев
                  07.12.2019, 11:35
                  Пожалуйста. По умолчанию в тело сообщения можно вставлять только текстовый контент. Для того чтобы в тело можно было вставлять HTML элементы нужно заменить метод textContent на innerHTML:
                  toastBody.innerHTML = body;
                  
                  Пример доступен по этой ссылке.
              2. Алексей
                Алексей
                07.12.2019, 09:05
                Александр, Здравствуйте.
                А возможно к Toast добавить ещё и звуковое оповещение?
                Войдите, пожалуйста, в аккаунт, чтобы оставить комментарий.