Context Menu — это пользовательский интерфейс, позволяющий предоставлять интерактивные опции при клике правой кнопкой мыши на элементе. В SvelteKit его реализация опирается на реактивность фреймворка и возможности DOM для обработки событий. Важной особенностью является динамическое управление состоянием видимости и позиции меню.
Для отображения контекстного меню требуется хранить несколько ключевых состояний:
<script>
import { writable } from 'svelte/store';
const menuVisible = writable(false);
const menuPosition = writable({ x: 0, y: 0 });
function openMenu(event) {
event.preventDefault();
menuPosition.set({ x: event.clientX, y: event.clientY });
menuVisible.set(true);
}
function closeMenu() {
menuVisible.set(false);
}
</script>
contextmenu, предотвращающий стандартное поведение браузера
и задающий позицию меню.Для корректной работы контекстного меню важно правильно привязать события к целевому элементу и к документу:
<div on:contextmenu={openMenu} class="target-element">
Правый клик на этом элементе
</div>
{#if $menuVisible}
<ul class="context-menu" style="top: {$menuPosition.y}px; left: {$menuPosition.x}px;">
<li on:click={() => { console.log('Option 1'); closeMenu(); }}>Option 1</li>
<li on:click={() => { console.log('Option 2'); closeMenu(); }}>Option 2</li>
<li on:click={() => { console.log('Option 3'); closeMenu(); }}>Option 3</li>
</ul>
{/if}
{#if $menuVisible}
обеспечивает реактивное отображение меню только при необходимости.style="top: {$menuPosition.y}px; left: {$menuPosition.x}px;"
позволяет меню появляться в точке клика.on:click, который выполняет действие и закрывает меню.Контекстное меню должно быть визуально отделено от контента и корректно отображаться на разных разрешениях экрана:
.context-menu {
position: fixed;
background-color: #ffffff;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
list-style: none;
padding: 8px 0;
margin: 0;
z-index: 1000;
min-width: 150px;
}
.context-menu li {
padding: 8px 16px;
cursor: pointer;
}
.context-menu li:hover {
background-color: #f0f0f0;
}
В SvelteKit можно использовать реактивные массивы для генерации пунктов меню:
<script>
const menuItems = [
{ label: 'Cut', action: () => console.log('Cut') },
{ label: 'Copy', action: () => console.log('Copy') },
{ label: 'Paste', action: () => console.log('Paste') },
];
</script>
{#if $menuVisible}
<ul class="context-menu" style="top: {$menuPosition.y}px; left: {$menuPosition.x}px;">
{#each menuItems as item}
<li on:click={() => { item.action(); closeMenu(); }}>{item.label}</li>
{/each}
</ul>
{/if}
{#each} позволяет легко
добавлять, удалять или менять пункты меню без изменения структуры
разметки.Чтобы меню автоматически закрывалось при клике вне его области, применяют слушатель документа:
<script>
import { onMount, onDestroy } from 'svelte';
onMount(() => {
const handleClickOutside = (event) => {
const menu = document.querySelector('.context-menu');
if (menu && !menu.contains(event.target)) {
closeMenu();
}
};
document.addEventListener('click', handleClickOutside);
onDestroy(() => {
document.removeEventListener('click', handleClickOutside);
});
});
</script>
onMount гарантирует
регистрацию события после рендера компонента.!menu.contains(event.target)
определяет, был ли клик вне меню.onDestroy
предотвращает утечки памяти.fade или slide, для
плавного отображения меню.<script>
import { fade } from 'svelte/transition';
</script>
{#if $menuVisible}
<ul class="context-menu" style="top: {$menuPosition.y}px; left: {$menuPosition.x}px;" transition:fade>
{#each menuItems as item}
<li on:click={() => { item.action(); closeMenu(); }}>{item.label}</li>
{/each}
</ul>
{/if}
Использование fade делает взаимодействие с контекстным
меню более естественным и современным, повышая UX приложения.
Context Menu в SvelteKit сочетает простоту реактивного фреймворка с гибкостью кастомизации. Управление состоянием через store, динамическое создание пунктов и интеграция с DOM событиями создают мощный инструмент для интерактивных веб-интерфейсов.