Intro
Я заметил этот пост о создании React Modal, поэтому я решил опубликовать свой вариант Svelte Modal, но с большим количеством функций и возможностью многократного использования.
Итак, для этого модала вы можете отобразить его и изменить текст и заголовок, просто установив значения магазина.
Вы также сможете закрыть модальное окно, щелкнув мышью вне модального окна, нажав клавишу Escape или нажав кнопку OK.
Это небольшая вариация компонента, который я создал для своего участия в хакатоне redis, где он использовался для отображения сообщений об ошибках.
Шаг за шагом
Начните с открытия терминала/консоли
Перейдите в директорию, в которой вы хотите разместить проект
Запустите
npm create vite@latest
Введите имя проекта, в моем случае svelte-modal
Выберите svelte в качестве фреймворка
Выберите обычный svelte
Как сказано в инструкции, перейдите в каталог и запустите
npm install
Я ленив и не люблю писать много CSS, поэтому для этого я буду использовать picocss.
Итак, запустите
npm install @picocss/pico
Запустите сервер разработчиков с
npm run dev
Теперь вы должны увидеть это в браузере.
Давайте приступим к коду!
Перейдите к файлу App.svelte в папке src. Он содержит шаблон для страницы, которую вы только что открыли в браузере.
Давайте удалим его и заменим на:
<script>
</script>
<main>
<button>Show modal</button>
</main>
Перейдем к app.css
и просто удалим все содержимое, так как оно не нужно.
Теперь импортируем pico.css
перейдем в main.js
и добавим следующее
import '@picocss/pico/css/pico.min.css';
в верхней части файла.
Теперь это должно выглядеть следующим образом:
import '@picocss/pico/css/pico.min.css';
import './app.css';
import App from './App.svelte';
const app = new App({
target: document.getElementById('app'),
});
export default app;
Этот модал будет использовать хранилище Svelte. В этом магазине будет храниться сообщение модала, заголовок и состояние открытия/закрытия. Использование магазина означает, что мы сможем запускать показ модала как из компонентов Svelte, так и из обычного кода Javascript.
Давайте создадим новую папку stores
внутри папки src/lib
. Создайте новый файл в папке stores
с именем index.js
.
Поместите в него приведенный ниже код. При желании вы можете установить заголовок и сообщение по умолчанию на любое удобное для вас значение.
import { writable } from 'svelte/store';
export const modal = writable({ open: false, title: 'Default title', message: 'Default message' });
Теперь магазин готов к использованию.
Давайте создадим собственно модальный компонент. Обычно я создаю папку components, но для этого примера мы просто поместим файл в папку ‘src/lib’.
Создадим файл с именем Modal.svelte
.
В этот файл мы поместим приведенный ниже код, я объясню, что он делает немного позже.
<script>
import { modal } from '../lib/stores/';
const close = () => ($modal.open = false);
const handle_keydown = (e) => {
if (e.key === 'Escape') return close();
};
</script>
<svelte:window on:keydown|once={handle_keydown} />
<dialog open on:click|self|preventDefault={close}>
<article>
<h3>{$modal.title}</h3>
<p>
{$modal.message}
</p>
<footer>
<button on:click|once={close}>OK</button>
</footer>
</article>
</dialog>
Давайте вернемся к файлу App.svelte
и подключим его, чтобы можно было все опробовать.
<script>
import Modal from './lib/Modal.svelte';
import { modal } from './lib/stores/';
</script>
<main>
{#if $modal.open == true}
<Modal />
{/if}
<button on:click={() => ($modal.open = true)}>Show modal</button>
</main>
Теперь у нас есть вот это:
И если нажать на кнопку:
Итак, мы импортируем компонент Modal и модальный магазин.
Мы помещаем компонент Modal внутрь Svelte-if. $modal ссылается на магазин, поэтому мы показываем компонент, только если $modal.open
— true.
Теперь у нас есть модальное окно, которое будет закрыто, если щелкнуть мышью за пределами модального окна, нажать кнопку escape на клавиатуре или нажать кнопку ok модального окна. Его можно отобразить из любого места, просто импортировав магазин и установив open в true, и таким же образом можно установить заголовок и сообщение для отображения различных вещей, например, сообщений об ошибках.
Теперь давайте углубимся в код, который заставляет это работать. Учитывая функциональность, которую он обеспечивает, код удивительно мал.
Вот компонент Modal.svelte
.
<script>
import { modal } from '../lib/stores/';
const close = () => ($modal.open = false);
const handle_keydown = (e) => {
if (e.key === 'Escape') return close();
};
</script>
<svelte:window on:keydown|once={handle_keydown} />
<dialog open on:click|self|preventDefault|once={close}>
<article>
<h3>{$modal.title}</h3>
<p>
{$modal.message}
</p>
<footer>
<button on:click|once={close}>OK</button>
</footer>
</article>
</dialog>
Импортируйте магазин, чтобы его можно было использовать.
import { modal } from '../lib/stores/';
Функция, которая закроет модальное окно, установив магазин.
const close = () => ($modal.open = false);
Обработчик для keydown, который будет показан немного ниже, вызывая функцию close() только при нажатии escape.
const handle_keydown = (e) => {
if (e.key === 'Escape') return close();
};
В Svelte мы можем использовать специальный тег svelte:window. Здесь мы используем его для привязки обработчика событий для нажатия клавиши к объекту окна, как это можно сделать в обычном javascript.
Он использует специальный модификатор DOM once
. Благодаря использованию once
слушатель удаляет себя после выполнения одного раза, что может быть полезно во многих ситуациях
<svelte:window on:keydown|once={handle_keydown} />
В pico.css модалы легко создаются с помощью элемента с элементом внутри. Это не специальные элементы, а обычные html-элементы.
Но давайте проанализируем приведенный ниже код. Существует on:click
слушатель, привязанный к элементу <dialog>
, поэтому полупрозрачная область вне модального поля. И запускает функцию close(), заставляя диалог закрыться.
<dialog open on:click|self|preventDefault|once={close}>
При использовании self
функция on:click сработает только в том случае, если мы явно щелкнем в любом месте элемента <dialog>
, то есть на фоне. Без этого on:click также сработает, если щелкнуть в любом месте модального окна. Удобная функция 🙂
preventDefault
не должен быть нужен, но я поместил его сюда, потому что хотел показать его. Она предотвращает поведение по умолчанию и является тем же самым, что и использование preventDefault() в обработчике событий. Это может быть удобно, если вы, например, хотите определить встроенную функцию для обработчика on:click, например:
on:submit|preventDefault={(e)=>do something simple}
Svelte полон таких умных вещей, как эта, проверьте документацию, если вам интересно узнать о других модификаторах DOM.
Надеюсь, вы чему-то научились. Это было утомительно писать, я буду писать devlogs. 😉