Контекстное меню – это меню, которое появляется при клике правой кнопкой мыши по экрану. Обычно такие меню используются для упрощения выполнения избранных действий, вроде сортировки папок и файлов, открывания нового окна приложения или доступа к настройкам системы.
Многие годы термин «контекстное меню» относится в первую очередь к нативным приложениям. Однако теперь у нас есть возможность извлечь из него преимущества и в веб-приложениях. В качестве примера можно привести менеджер файлов в Gmil. Это меню реализовано при помощи кода javascript:
В будущем у нас будет возможность создавать контекстные меню для сайтов, основанных на HTML5. Предлагаем вам познакомиться с этим подходом.
Разработка контекстного меню
HTML5 представил нам 2 новых элемента: menu и menuitem, и они позволяют вам создавать контекстные меню. Для того чтобы браузер расценивал элемент menu как «контекстное меню», нам нужно установить тип меню как context, а также задать ему уникальный ID.
Ниже представлен пример, в котором мы создаем контекстное меню с этими свойствами.
Edit Content
Email Selection
У нас также остается возможность добавлять подменю, разветвляя элемент menu следующим образом:
Edit Content
Email Selection
Facebook
Twitter
Теперь, для того, чтобы контекстное меню появилось на экране при клике правой кнопкой мыши, мы используем новый HTML-атрибут под названием contextmenu. Этот атрибут используется для того, чтобы определять меню с указанным ID. Учитывая наш вышеприведенный пример, мы можем определить наше контекстное меню при помощи contextmenu=context-menu-id.
Мы можем задать атрибут в тэге body, если хотим использовать контекстное меню на всей странице. Мы также можем добавить его в HTML-элемент, чтобы данное меню использовалось исключительно внутри данного элемента.
Теперь новое контекстное меню появится внутри меню Operating System, как видно на примере ниже.
Уверены, что многие из вас видели контекстные меню, в которых используются иконки. В некоторых случаях иконка может стать отличным визуально вспомогательным элементом, который помогает пользователям найти меню. Вдобавок он также дает пользователям возможность понять, для чего предназначено данное меню.
Edit Content
Email Selection
Facebook
Twitter
Вот что мы увидим в окне браузера.
На данном этапе наше новое контекстное меню не будет работать при нажатии. Однако мы можем очень просто привести его в чувства посредством небольшого кода javascript. В нашем примере меню называется Email Selection. Это меню позволяет пользователям отправлять выделенный текст по электронной почте.
Чтобы оно заработало, давайте добавим функцию, которая позволит пользователям использовать выделенный код.
Function getSelectedText() {
var text = "";
if(window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
return text;
};
Затем мы создаем еще одну функцию, предположим sendEmail(), которая открывает email-клиент. Темой письма будет введенный текст из заголовка документа, а тело письма будет заполнено выделенным текстом.
Function sendEmail() {
var bodyText = getSelectedText();
window.location.href = "mailto:?subject="+ document.title +"&body="+ bodyText +"";
};
Наконец, мы добавляем эту функцию в наше меню посредством атрибута onclick.
Email Selection
Ранее мы уже рассказывали вам о том, как использовать HTML5 EditableContent, который позволяет нам редактировать веб-контент прямо на странице. Мы можем использовать данную функцию, добавив ее в наше меню под названием “Edit Content”.
В завершение
Лично мы очень обрадовались этой новой функции. Мы видим в ней множество возможностей. К сожалению, на момент написания данного материала, только Firefox поддерживал это свойство. Надеемся, что и другие браузеры скоро к нему подключатся.
Ниже можно просмотреть демо (работает только в Firefox).
16.11.15 1.2KВ этой статье я приведу обзор двух элементов HTML5 : и , которые входят в спецификацию интерактивных элементов. Эти два элемента являются одними из тех, которые в среде разработчиков обсуждаются в последнюю очередь, вероятно, из-за отсутствия их поддержки в основных браузерах. Firefox — единственный браузер, в котором реализована поддержка этого тега.
Элемент Menu против элемента NavКогда мы говорим о menu , важно не путать его с тегом , который является элементом навигации HTML . Он создает блок навигации веб-страницы с ссылками, которые позволяют перемещаться по разделам одной страницы или на другие страницы сайта.
Элемент представляет собой набор команд меню. Принцип его работы похож на стационарные или мобильные приложения. Стационарные приложения обычно используют меню для выполнения различных задач. Например, меню «Размытие » в Photoshop . Оно предназначено для выполнения задач по размытию выбранного слоя:
Меню «Размытие» в Photoshop
В этом заключается основное отличие между этими двумя элементами; должен содержать ссылки, которые помогают пользователям перемещаться по веб-страницам, в то время как позволяет выполнять определенные задачи.
Использование элементаЭлемент предназначен для создания контекстных меню, всплывающих меню и меню панелей инструментов. Но поддержка последних двух функций тега еще не реализованы ни в одном из браузеров, в том числе и в Firefox .
В данный момент мы сосредоточим свое внимание на создании контекстного меню.
Контекстное менюКонтекстное меню выводится, когда мы в приложении кликаем правой кнопкой мыши. Варианты отображения зависят от того, в каком месте пользователь кликнул мышью:
Оригинальное контекстное меню в OS X и Ubuntu
Вариант JavaScriptМожно добавлять контекстные меню на веб-страницах и через JavaScript или JQuery -плагин. Проблема заключается в том, что эти методы используют огромное количество разметки, а сам скрипт удаляет оригинальное контекстное меню браузера. Это может привести к появлению реализации, не соответствующей ожиданиям пользователя:
Настроенное контекстное меню в Google Drive
Оригинальное решениеЭлементы и будут добавлять новые пункты в версию оригинального контекстного меню. В приведенном ниже примере, мы добавим в тег новый пункт контекстного меню под названием «Hello World «:
Hello World
Основными частями приведенного выше фрагмента кода являются атрибуты — id , type и contextmenu , которые определяют тип меню как context , а также область, где должно отображаться новое меню.
В нашем случае при выполнении клика правой кнопкой мыши новое меню будет выводиться в любом месте документа, так как мы назначили его с помощью атрибута contextmenu для всего раздела body .
Можно ограничить диапазон в пределах определенного раздела страницы, присвоив значение атрибуту contextmenu в элементах , , и т.д.:
Hello World
Когда мы просматриваем этот код в браузере (в настоящее время, только в Firefox ), мы увидим, что menuitem , который мы объявили, выводится в самом верху списка:
Новый пункт меню, «Hello World», который загружается как часть оригинального контекстного меню
Добавление подменю и иконокПодменю представляют собой группу элементов со связанными или аналогичными действиями. Меню «Вращение изображения » в Photoshop является прекрасным примером этого. Оно включает в себя несколько пунктов подменю, которые позволяют пользователю выбрать угол поворота, а также направление вращения.
Использование элемента menu при добавлении подменю является простым и понятным. Вложите еще один элемент с атрибутом label , чтобы объявить имя меню, например:
Повернуть на 90 градусов Повернуть на 180 градусов Отразить по горизонтали Отразить по вертикали
Когда мы запустим этот код в браузере, мы обнаружим новое меню с четырьмя пунктами подменю:
ИконкиТакже был введен новый атрибут icon для добавления иконок слева от пунктов меню. Стоит отметить, что этот атрибут применим только для элемента . Укажите путь к иконке для icon , например, так:
Повернуть на 900 Повернуть на 1800 Отразить по горизонтали Отразить по вертикали
И в нашем меню появятся иконки, как вы можете видеть на рисунке ниже:
Каждый пункт подменю теперь иллюстрирован иконкой
Добавление функций в менюМы создали то, что выглядит как контекстное меню, но оно еще не работает, как функциональное меню. Мы можем исправить это с помощью JavaScript .
Возьмем наш пример с подменю «Повернуть изображение » и добавим функцию, которая будет поворачивать изображение, по которому мы кликнули правой кнопкой мыши. Преобразования и переходы CSS3 могут выполнить вращение изображения в браузере. Вот стиль, который будет поворачивать изображение на 90 градусов:
Rotate-90 { transform: rotate(90deg); }
Указав стиль, мы должны написать функцию, чтобы применить его к изображению.
Веб-приложения на сегодняшний день становятся новым шагом на пути развития веба. Это уже далеко не обычные информационные сайты. В качестве примера передовых веб-приложений можно привести Gmail и Dropbox. С ростом функциональности, доступности и полезности веб-приложений растет и потребность в увеличении эффективности их использования. В данном руководстве будет рассмотрено создание такой полезной штуки, как собственное контекстное меню, и в частности:
На вашем компьютере клик правой кнопкой мыши на рабочем столе вызовет контекстное меню операционной системы. Отсюда вы, вероятно, можете создать новую папку, получить какую-то информацию и сделать что-нибудь еще. Контекстное меню в браузере позволяет, например, получить информацию о странице, посмотреть ее исходники, сохранить изображение, открыть ссылку в новой вкладке, поработать с буфером обмена и всякое такое. Причем набор доступных действий зависит от того, куда именно вы кликнули, то есть от контекста. Это стандартное поведение, закладываемое разработчиками браузера [И расширений к нему ].
Веб-приложения постепенно начинают заменять стандартные контекстные меню своими собственными. Отличными примерами являются все те же Gmail и Dropbox. Вопрос лишь в том, как сделать свое контекстное меню? В браузере при клике правой кнопкой мыши срабатывает событие contextmenu. Нам придется отменить поведение по умолчанию и сделать так, чтобы вместо стандартного меню выводилось наше собственное. Это не так уж сложно, но разбираться будем пошагово, так что выйдет довольно объемно. Для начала создадим базовую структуру приложения, чтоб разрабатываемый пример не был совсем уж оторван от реальности.
Список задач Представим, что мы создаем приложение, позволяющее вести список задач. Я понимаю, вы уже наверняка неимоверно устали от всех этих списков задач, но пусть будет. Страница приложения содержит список незавершенных задач. Для каждой задачи доступен типичный набор действий CRUD: получить информацию о задаче, добавить новую, редактировать, удалить.Пример результата есть на CodePen . Можете заглянуть туда сразу, если лень читать или хотите убедиться, что действительно заинтересованы в дальнейшем чтении. Ну а пока приступим к пошаговой разработке задуманного. Я буду использовать некоторые современные фишки CSS и создам простейший список задач на data-атрибутах. Также воспользуюсь сбросом стилей от Эрика Мейера и сброшу свойство box-sizing для всех элементов в border-box:
*,
*::before,
*::after {
box-sizing: border-box;
}
Я не буду использовать префиксы в CSS, но в демо на CodePen включен автопрефиксер.
Но для начала давайте добавим к меню ID, чтобы его проще было получать посредством JS. Также добавим переменную состояния меню menuState и и переменную с активным классом. Получились три переменных:
var menu = document.querySelector("#context-menu");
var menuState = 0;
var active = "context-menu--active";
Едем дальше. Пересмотрим функцию contextMenuListener и добавим toggleMenuOn, отображающую меню:
function contextMenuListener(el) {
el.addEventListener("contextmenu", function(e) {
e.preventDefault();
toggleMenuOn();
});
}
function toggleMenuOn() {
if (menuState !== 1) {
menuState = 1;
menu.classList.add(active);
}
}
На данный момент правой кнопкой мыши уже можно вызвать наше контекстное меню. Но нельзя сказать, что оно работает правильно. Во-первых, оно находится совсем не там, где хотелось бы. Для устранения проблемы понадобится немного математики. Во-вторых, закрыть это меню пока невозможно. С учетом того, как работают обычные контекстные меню, хотелось бы, чтоб наша его реализация закрывалась при клике не меню и при нажатии Escape. Помимо этого при правом клике вне нашего меню оно должно закрыться, а вместо него требуется открытие меню по умолчанию. Давайте попробуем все это решить.
Много кода
(function() { "use strict"; /////////////////////////////////////// /////////////////////////////////////// // // H E L P E R F U N C T I O N S // ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ // /////////////////////////////////////// /////////////////////////////////////// /** * Some helper functions here. * Здесь сами вспомогательные функции. */ /////////////////////////////////////// /////////////////////////////////////// // // C O R E F U N C T I O N S // ФУНКЦИИ ЯДРА // /////////////////////////////////////// /////////////////////////////////////// /** * Variables. * Переменные. */ var taskItemClassName = "task"; var menu = document.querySelector("#context-menu"); var menuState = 0; var activeClassName = "context-menu--active"; /** * Initialise our application"s code. * Инициализация кода нашего приложения. */ function init() { contextListener(); clickListener(); keyupListener(); } /** * Listens for contextmenu events. * Обработка события contextmenu. */ function contextListener() { } /** * Listens for click events. * Обработка события click. */ function clickListener() { } /** * Listens for keyup events. * Обработка события keyup. */ function keyupListener() { } /** * Turns the custom context menu on. * Отображение контекстного меню. */ function toggleMenuOn() { if (menuState !== 1) { menuState = 1; menu.classList.add(activeClassName); } } /** * Run the app. * Запуск приложения. */ init(); })();
Функция инициализации остается такой же. Первое изменение затрагивает contextListener, ведь мы хотим сохранять в taskItemInContext элемент, на который кликнул пользователь, а функция clickInsideElement как раз его и возвращает:
function contextListener() {
document.addEventListener("contextmenu", function(e) {
taskItemInContext = clickInsideElement(e, taskItemClassName);
if (taskItemInContext) {
e.preventDefault();
toggleMenuOn();
positionMenu(e);
} else {
taskItemInContext = null;
toggleMenuOff();
}
});
}
Мы сбрасываем ее в null, если правый клик произошел не по элементу списка. Ну и возьмемся за clickListener. Как я упоминал ранее, для простоты мы просто будем выводить информацию в консоль. Сейчас при отлавливании события click производится несколько проверок и меню закрывается. Внесем коррективы и начнем обрабатывать клик внутри контекстного меню, выполняя некоторое действие и лишь после этого закрывая меню:
function clickListener() {
document.addEventListener("click", function(e) {
var clickeElIsLink = clickInsideElement(e, contextMenuLinkClassName);
if (clickeElIsLink) {
e.preventDefault();
menuItemListener(clickeElIsLink);
} else {
var button = e.which || e.button;
if (button === 1) {
toggleMenuOff();
}
}
});
}
Вы могли заметить, что вызывается функция menuItemListener. Ее мы определим чуть позже. Функции keyupListener, resizeListener и positionMenu оставляем без изменений. Функции toggleMenuOn и toggleMenuOff отредактируем незначительно, изменив имена переменных для лучшей читаемости кода:
function toggleMenuOn() {
if (menuState !== 1) {
menuState = 1;
menu.classList.add(contextMenuActive);
}
}
function toggleMenuOff() {
if (menuState !== 0) {
menuState = 0;
menu.classList.remove(contextMenuActive);
}
}
Наконец реализуем menuItemListener:
function menuItemListener(link) {
console.log("Task ID - " +
taskItemInContext.getAttribute("data-id") +
", Task action - " + link.getAttribute("data-action"));
toggleMenuOff();
}
На этом разработка функциональности заканчивается.
Кодовая база этого руководства
Собственное контекстное меню довольно редко применяется в интерфейсе веб-страницы. Ведь пользователю совершенно не очевидно, что на каком-то элементе надо щёлкнуть не левой, а правой кнопкой мыши и выбрать пункт из списка. К тому же не все посетители сайтов любят использовать правую кнопку мыши, а на смартфонах её вообще нет, только имитация. Несмотря на эти особенности в HTML5 есть возможность создавать собственные контекстные меню, реализовано это пока только в Firefox, и то весьма своеобразно.
Для начала давайте посмотрим, как вообще создаются разные меню. Для этого используется комбинация тегов и (пример 1).
Пример 1. Контекстное меню
HTML5 IE Cr Op Sa Fx
Контекстное меню
Атрибут contextmenu сообщает, что наше меню является контекстным и одновременно указывает на тег с заданным идентификатором (в данном случае edit ). Пока ни один браузер не понимает приведённый пример, включая Firefox. Для него вместо тега следует вставить нестандартный тег (пример 2).
Пример 2. Меню в Firefox
HTML5 IE Cr Op Sa Fx
Контекстное меню
Код получился невалидным, зато при щелчке по картинке в Firefox появляется красивое меню (рис. 1).
Рис. 1. Контекстное меню
Пока это меню не работает нужным образом, так что переделаем его. Для начала добавим возле пункта меню иконку с помощью атрибута icon , так меню получится симпатичнее. В качестве значения указывается относительный или абсолютный путь к графическому файлу. Затем надо сделать, чтобы при нажатии на пункт меню происходило какое-то действие. Для этого воспользуемся событием onclick и с его помощью будем вызывать нужную функцию. В примере 3 показано создание контекстного меню для текста, если в нём выбрать «Править», то текст можно редактировать. На деле же применяется скрытое текстовое поле, которое становится видимым при вызове функции edit(), сам же текст на время редактирования скрывается. После нажатия на Enter текст из формы вставляется на место текстового абзаца, создавая впечатление, что именно его мы и правили. Форма же после завершения редактирования прячется вновь.
Пример 3. Редактирование текста
HTML5 IE Cr Op Sa Fx
Контекстно меню #edit { width: 200px; border: 1px solid #ccc; display: none; } function edit() { document.getElementById("text").style.display = "none"; document.getElementById("edit").style.display = "block"; document.getElementById("edit").value = document.getElementById("text").innerHTML; document.getElementById("edit").focus(); } function text() { document.getElementById("text").innerHTML = document.getElementById("edit").value; document.getElementById("edit").style.display = "none"; document.getElementById("text").style.display = "block"; }
Пример текста
Вид нового меню показан на рис. 2.
Рис. 2. Меню с иконкой
Как видно из примера, создание контекстного меню ничем не отличается от создания других интерактивных элементов. При нажатии на пункт меню вызывается наша функция с помощью обработчика onclick , а дальше эта функция будет делать то, что мы пожелаем. Firefox 8 стал первым браузером, который начал поддерживать контекстные меню HTML5, но вызывает удивление, почему разработчики Firefox ввели для меню свой собственный нестандартный тег . Здесь возможны несколько вариантов развития событий:
Остаётся только ждать ответа других браузеров, в которых тег наконец-то будет реализован, а также разные меню на его основе.