Как сделать всплывающее меню на javascript

«Живые меню» или «Как сделать красиво с помощью CSS и JavaScript»

Наверное, никто не сможет поспорить с утверждением, что главное в любой web-страничке — удобство для пользователя. После того, как мы выложили наше творение в сеть, мы сразу начинаем предпринимать массу усилий для того, чтобы привлечь на свой сайт максимум посетителей. Но привлечь мало — надо еще сделать все для того, чтобы посетителям наш сайт понравился, чтобы им захотелось остаться, а потом приходить снова и снова. Для этого недостаточно наполнить страницу интересным содержанием, нужно еще сделать ее красивой и, самое главное, удобной в использовании. На Западе для предоставления потребителям максимума удобств существует даже специальная профессия — специалист по usability. Если вас заинтересовало, что это значит, узнать подробности вы можете на страничке Артемия Лебедева http://www.design.ru/kovodstvo. А в нашей статье речь пойдет несколько о другом — о том, как превратить навигацию по вашему сайту в сплошное удовольствие для посетителя.

Хочу заранее предупредить, что все примеры, приведенные в данной статье, предназначены только для браузеров Internet Explorer версии 4.0 и выше, т.к. цель этой статьи — не научить вас кроссбраузерному DHTML, а лишь показать, каких интересных эффектов можно достичь, манипулируя свойствами CSS при помощи JavaScript. Что касается аналогичных эффектов для браузеров Netscape, которые намного меньше распространены в России, упомяну лишь, что для совместимости с ними нужно будет проделать небольшую дополнительную работу — написать скрипт, определяющий версию браузера при загрузке страницы, и несколько изменить функции, управляющие свойствами CSS.

Также напомню, что некоторые пользователи отключают в своих браузерах графику для ускорения загрузки страниц. Поэтому, если вы делаете меню для навигации по вашему сайту с помощью графических элементов, не забывайте снабдить рисунки подробными описаниями в атрибуте alt. Желательно также создать альтернативное текстовое меню — обычно его делают внизу страницы в виде строчки, содержащей ссылки на основные разделы сайта.

Графическое меню с подразделами, реагирующее на действия пользователя

Итак, давайте попробуем создать красивое навигационное меню, реагирующее на действия посетителя вашей странички (вернее, на действия его мышки). Описываемое здесь меню подойдет вам, если разделов на сайте не слишком много, и каждый из них содержит небольшое число подразделов. Посетитель при загрузке страницы будет видеть картинки с названиями разделов, а если он наведет курсор мышки на одну из этих картинок, из-под нее «выпадет» список доступных в данном разделе подразделов.

Обратите внимание: слои с нашими картинками должны быть абсолютно позиционированы. Свойство z-index со значением, большим единицы, задано для того, чтобы выпадающие меню оказывались поверх других элементов страницы. Советую разместить навигационное меню на странице так, чтобы списки подразделов, выпадая, оказывались поверх баннера или какого-нибудь другого малозначительного графического элемента. Если посетитель, читая что-то интересное, случайно наведет мышку на название раздела (многие любят, читая, «возить» мышкой по странице) и поверх текста вдруг вывалится список подразделов, ему это вряд ли понравится.

Теперь создадим пример слоя, который покажет нам кусочек нашего меню в действии. Точнее, нам понадобится два разных слоя — видимый и спрятанный, который будет появляться при наведении курсора мышки на видимый. Внутри слоев будут содержаться наши картинки, расположенные точно друг под другом. Для этого следует прибегнуть к абсолютному позиционированию слоев или к простенькой табличке, состоящей из одного столбца и двух строк: в первой содержится видимая кнопка, а во второй — спрятанные. В простейшем случае это будет выглядеть так:

Обратите внимание — для спрятанного слоя обязательно должен быть задан уникальный идентификатор, в нашем случае это — Идентификатор нужен для того, чтобы программа JavaScript, которую мы напишем чуть позже, могла обратиться к конкретному элементу страницы.

Когда мышка посетителя нашей странички окажется над видимым слоем, для этого слоя произойдет событие MouseOver, а когда курсор вновь уйдет за пределы слоя — произойдет событие MouseOut. Все, что нам осталось теперь сделать, — это создать обработчики для этих событий мышки.

Конечно же, можно записать значения обработчиков событий непосредственно в тэгах слоя, но, во-первых, это удобно лишь до той поры, пока слоев один-два, а если мы собираемся создать полноценную навигационную панель, у нас их будет значительно больше. Во-вторых, правила «хорошего тона» в DHTML предписывают задать программу JavaScript, называемую функцией, в разделе в тэге-контейнере

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

Читайте также:  Как сделать самый большой фейерверк в майнкрафт

Обратите внимание, что при задании функций мы не использовали явных ссылок на уникальный идентификатор слоя, а воспользовались заданием переменной obj. В языке JavaScript можно присваивать значение и тип переменных автоматически, и для каждого нового подменю мы можем использовать новое значение переменной, что позволит нам использовать одни и те же функции для обработки событий в разных слоях.

Добавим теперь атрибуты onmouseover (курсор находится над слоем) и onmouseout (курсор находится вне слоя) в тэг

Но этого недостаточно. Нам нужно еще, чтобы список подразделов оставался видимым, когда наш посетитель захочет нажать на нем одну из ссылок. Для этого нужно прописать невидимому слою абсолютно аналогичные обработчики событий. Вам с первого взгляда может показаться, что при такой постановке вопроса список подразделов может вдруг «возникнуть из ничего», если наш гость случайно заедет курсором в область его расположения, но на самом деле это не так. Логика браузера Internet Explorer такова, что скрытые объекты нечувствительны к событиям мыши, поэтому обработчики событий будут действовать лишь тогда, когда слой станет видимым после наведения курсора на область названия раздела. Окончательная запись кода нашей странички будет выглядеть так:

Осталось только прописать ссылки к картинкам, да еще неплохо было бы для видимого слоя, если он по вашему замыслу не будет являться самостоятельной ссылкой, задать свойство cursor: hand; чтобы посетителю стало ясно, что это не просто картинка, а область управления.

Если теперь добавить абсолютно позиционированный баннер в область невидимого слоя и задать ему z-index равным единице, то наше меню будет выпадать поверх баннера.

Вот и все, теперь для создания полноценной навигационной панели вам осталось только добавить нужное количество видимых и невидимых слоев, не забывая прописывать каждому невидимому слою свой уникальный идентификатор и обращаться именно к нему в соответствующих обработчиках событий. Если вам лень высчитывать значения top и left для абсолютного позиционирования элементов страницы, вы можете с успехом поместить слои внутрь ячеек таблицы, но свойство position: absolute; (без значений top и left) должно остаться, иначе ваша табличка расползется!

Источник

Собственное контекстное меню с использованием JavaScript

Что есть контекстное меню?

Если верить Википедии, контекстное меню — меню, появляющееся при взаимодействии пользователя с графическим интерфейсом (при нажатии правой кнопки мыши). Контекстное меню содержит ограниченный набор возможных действий, который обычно связаны с выбранным объектом.

На вашем компьютере клик правой кнопкой мыши на рабочем столе вызовет контекстное меню операционной системы. Отсюда вы, вероятно, можете создать новую папку, получить какую-то информацию и сделать что-нибудь еще. Контекстное меню в браузере позволяет, например, получить информацию о странице, посмотреть ее исходники, сохранить изображение, открыть ссылку в новой вкладке, поработать с буфером обмена и всякое такое. Причем набор доступных действий зависит от того, куда именно вы кликнули, то есть от контекста. Это стандартное поведение, закладываемое разработчиками браузера [И расширений к нему].

Веб-приложения постепенно начинают заменять стандартные контекстные меню своими собственными. Отличными примерами являются все те же Gmail и Dropbox. Вопрос лишь в том, как сделать свое контекстное меню? В браузере при клике правой кнопкой мыши срабатывает событие contextmenu. Нам придется отменить поведение по умолчанию и сделать так, чтобы вместо стандартного меню выводилось наше собственное. Это не так уж сложно, но разбираться будем пошагово, так что выйдет довольно объемно. Для начала создадим базовую структуру приложения, чтоб разрабатываемый пример не был совсем уж оторван от реальности.

Список задач

Представим, что мы создаем приложение, позволяющее вести список задач. Я понимаю, вы уже наверняка неимоверно устали от всех этих списков задач, но пусть будет. Страница приложения содержит список незавершенных задач. Для каждой задачи доступен типичный набор действий CRUD: получить информацию о задаче, добавить новую, редактировать, удалить.

Пример результата есть на CodePen. Можете заглянуть туда сразу, если лень читать или хотите убедиться, что действительно заинтересованы в дальнейшем чтении. Ну а пока приступим к пошаговой разработке задуманного. Я буду использовать некоторые современные фишки CSS и создам простейший список задач на data-атрибутах. Также воспользуюсь сбросом стилей от Эрика Мейера и сброшу свойство box-sizing для всех элементов в border-box:

Я не буду использовать префиксы в CSS, но в демо на CodePen включен автопрефиксер.

Создание базовой структуры

Откроем наш HTML-документ, накидаем шапку, контентную часть с некоторым списком задач и подвал. Я также подтяну Font Awesome и шрифт Roboto, чтобы сделать оформление немного лучше. Каждая задача должна содержать атрибут data-id, который в реальности брался бы из БД. Также каждая задача будет содержать список действий. Вот важные части разметки:

Если вы используете CodePen, можете в настройках включить автопрефиксер и подключение CSS-сброса. В противном случае придется делать все руками, если еще не автоматизировали этот процесс. Не забывайте, что наша цель — создание контекстного меню, так что обработка действий не будет реализована. А теперь давайте добавим еще немного CSS:

Читайте также:  Как сделать скрин во весь лист

Полный набор стилей (да и всего остального) представлен на CodePen. А здесь будут самые важные части кода, разметки и оформления. Но давайте уже наконец приблизимся к нашему контекстному меню.

Набросаем наше контекстное меню — разметка

Приводим наше меню в порядок — CSS

Уже была упомянута необходимость абсолютного позиционирования разрабатываемого меню. Кроме того, установим свойство z-index в 10. Не забывайте, что в вашем приложении может потребоваться другое значение. Это не все возможные стили, в демке наведены прочие красивости, но они уже зависят от ваших потребностей и не являются обязательными. Прежде чем переходить к JS, сделаем меню невидимым по умолчанию и добавим дополнительный класс для его отображения.

Разворачиваем наше контекстное меню — JavaScript

Начнем с того, что посмотрим, как зарегистрировать событие contextmenu. Откроем самовыполняющуюся функцию и отловим событие на всем документе. Также будем логировать событие в консоль, чтобы получить какую-то информацию:

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

Но для начала давайте добавим к меню ID, чтобы его проще было получать посредством JS. Также добавим переменную состояния меню menuState и и переменную с активным классом. Получились три переменных:

Едем дальше. Пересмотрим функцию contextMenuListener и добавим toggleMenuOn, отображающую меню:

На данный момент правой кнопкой мыши уже можно вызвать наше контекстное меню. Но нельзя сказать, что оно работает правильно. Во-первых, оно находится совсем не там, где хотелось бы. Для устранения проблемы понадобится немного математики. Во-вторых, закрыть это меню пока невозможно. С учетом того, как работают обычные контекстные меню, хотелось бы, чтоб наша его реализация закрывалась при клике не меню и при нажатии Escape. Помимо этого при правом клике вне нашего меню оно должно закрыться, а вместо него требуется открытие меню по умолчанию. Давайте попробуем все это решить.

Рефакторинг нашего кода

Вернемся и отредактируем contextListener:

Имея вспомогательную функцию, делающую за нас часть грязной работы, и отлавливая событие contextmenu на всем документе, мы можем теперь закрывать меню при клике вне его. Для этого добавим функцию toggleMenuOff и отредактируем contextListener:

Теперь нажмите правой кнопкой по элементу списка. А после — где-нибудь в другом месте документа. Вуаля! Наше меню закрылось и открылось стандартное. Затем сделаем нечто похожее самое для события click, чтобы не от одной правой кнопки оно закрывалось:

Этот кусок кода несколько отличается от предыдущего, потому что Firefox. После того, как правая кнопка мыши отжата, в Firefox срабатывает событие click, так что здесь нам приходится дополнительно убеждаться, что произошел действительно клик левой кнопкой. Теперь меню не моргает при правом клике. Давайте добавим похожий обработчик и на нажатие клавиши ESC:

Мы получили меню, которое открывается и закрывается как задумано, взаимодействующее с пользователем естественным образом. Давайте наконец отпозиционируем меню и попробуем обрабатывать события внутри него.

Позиционирование нашего контекстного меню

С учетом текущих HTML и CSS, наше меню отображается в нижней части экрана. Но нам-то хотелось бы, чтоб оно появлялось там, где произошел клик. Давайте исправим сие досадное упущение. Во-первых, добавим еще одну вспомогательную функцию, получающую точные координаты клика. Назовем ее getPosition и попробуем заставить обрабатывать разные причуды браузеров:

Наш первый шаг в позиционировании меню — подготовка трех переменных. Добавим их в соответствующий блок кода:

Создадим функцию positionMenu, принимающую единственный аргумент — событие. Пока что пусть она выводит координаты меню в консоль:

Отредактируем contextListener, чтобы начать процесс позиционирования:

Снова повтыкайте в контекстное меню и загляните в консоль. Убедитесь, что позиция действительно доступна и логируется. Мы можем использовать встроенные стили для задания свойств top и left посредством JS. Вот и новая версия positionMenu:

Как вы помните, по умолчанию наше меню скрыто, так что нельзя просто взять и посчитать его размеры. В нашем случае меню статическое, но при реальном применении его содержимое может меняться в зависимости от контекста, так что рассчитывать ширину и высоту лучше в момент открытия. Получим нужные величины внутри функции positionMenu:

Введем еще две переменных, но на этот раз для размеров окна:

Посчитаем их значения похожим образом:

В конечном счете давайте предположим, что хотим показывать меню не ближе, чем в 4 пикселях от края окна. Можно сравнить значения, как я говорил выше, и скорректировать позицию как-то так:

Сейчас наше меню ведет себя совсем хорошо. Осталось что-то сделать с ресайзом окна. Я уже говорил, как поступает Dropbox, но вместо этого мы будем закрывать контекстное меню. [Такое поведение куда ближе к стандартному] Добавим в функцию init следующую строку:

И напишем саму функцию:

Цепляем события к пунктам контекстного меню

Если ваше приложение сложнее данного примера, и у вас планируется динамическое содержимое контекстного меню, придется подробнее вникнуть в происходящее далее, чтобы самому додумать недостающие детали. В нашем приложении все проще, и есть всего одно меню с постоянным набором действий. Таким образом, можно быстро проверить, какой именно элемент был выбран, и обработать этот выбор. В нашем примере просто сохраним выбранный элемент в переменную и запишем в консоль его data-id и выбранное действие. Для этого отредактируем разметку меню:

Читайте также:  Как сделать рождественский вертеп мастер класс

Далее давайте закэшируем все нужные объекты:

Появилась переменная taskItemInContext, которой присваивается значение при правом клике по элементу списка. Она нам потребуется для логирования ID элементов. Также появились новые имена классов. Теперь пройдемся по функциональности.

Функция инициализации остается такой же. Первое изменение затрагивает contextListener, ведь мы хотим сохранять в taskItemInContext элемент, на который кликнул пользователь, а функция clickInsideElement как раз его и возвращает:

Мы сбрасываем ее в null, если правый клик произошел не по элементу списка. Ну и возьмемся за clickListener. Как я упоминал ранее, для простоты мы просто будем выводить информацию в консоль. Сейчас при отлавливании события click производится несколько проверок и меню закрывается. Внесем коррективы и начнем обрабатывать клик внутри контекстного меню, выполняя некоторое действие и лишь после этого закрывая меню:

Вы могли заметить, что вызывается функция menuItemListener. Ее мы определим чуть позже. Функции keyupListener, resizeListener и positionMenu оставляем без изменений. Функции toggleMenuOn и toggleMenuOff отредактируем незначительно, изменив имена переменных для лучшей читаемости кода:

Наконец реализуем menuItemListener:

На этом разработка функциональности заканчивается.

Некоторые замечания

Большой вопрос

Я выделил эту проблему в отдельный пункт, потому что это действительно важно после всего, что мы проделали. Задайтесь вопросом: действительно ли вам нужно собственное контекстное меню? Такие штуки — это круто, но прежде чем их использовать, вы должны убедиться, что это действительно полезно в вашем случае. Обычно пользователи ожидают привычного поведения приложения. Например, после правого клика по фотографии они ожидают получения возможности сохранить ее, скопировать ссылку и т. д. Отсутствие нужных пунктов в кастомном меню может их огорчить.

Совместимость с браузерами

Заключение и демо

Если вы тщательно все обдумали и уверены, что такая функциональность нужна вашему приложению, вы можете использовать разработанное меню. Конечно, оно может потребовать каких-либо изменений, но данное руководство подробно описывает процесс разработки, так что реализовывать свои поправки должно быть не так сложно.

Кодовая база этого руководства залита на GitHub и будет поддерживаться и, возможно, обновляться в течение долгого времени. А полное рабочее демо можно потыкать на CodePen.

От переводчика

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

Источник

Тестовое задание: выпадающее меню на чистом javascript

Два-три года назад откликнулся на вакансию фронтенд-разработчика контентных проектов в Mail.ru Group. В ответ стандартно получил просьбу выполнить тестовое задание. К сожалению, моего уровня оказалось недостаточно и мне пришёл отказ. Хочу поделиться тестовым заданием и своим кодом, который был написан в ходе его выполнения. Возможно кому-то пригодится такое простенькое выпадающее меню на нативном javascript.

Итак, задание формулировалось следующим образом:

Реализовать идеальное, на твой взгляд, «выпадающее меню» (dropdown).
Пример/черновик верстки http://jsfiddle.net/jawLmp4x/
Минимальные требования:
0. Никаких библиотек, только нативный js
1. Возможность отследить раскрытие/скрытие «выпадашки» и выбор элемента
2. Настройка раскрытия/скрытия по нажатию или наведению
Всё остальное на твое усмотрение, можно просто описать словами, что бы ты ещё улучшил, какую функциональность добавил и так далее.
P.S. Поддержка браузерами не имеет значения

Оценив задание, мне стало понятно, что для «идеальности» нужно выполнить весьма немало требований. За вечер успел накидать только базовый вариант без дополнительных возможностей. А утром выслал его, сопроводив описание остальных улучшений следующими словами.

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

Также возможно не до конца верно понял требования. Написал меню исходя из того, что в обоих вариантах (как при открытии по клику, так и при открытии плашек при наведении) пользователь должен выбрать пункт меню второго уровня, после чего выбранный пункт перекрашивается.

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

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

А меню из одной кнопки с выпадающим списком при наведении таким:

Вот такая пара сотен строк кода получилась:

Источник

Оцените статью
Как сделать своими руками
Adblock
detector