Какие события следует прослушивать, чтобы скрыть настраиваемое контекстное меню в JavaScript

Интересно, какие события я должен слушать, чтобы скрыть свое настраиваемое контекстное меню, элемент <div>, отображаемый из обработчика событий oncontextmenu, как и в собственном.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
4
0
1 472
2

Ответы 2

Используйте событие oncontextmenu.

el.addEventListener('contextmenu', function(ev) {
    ev.preventDefault();
    // here what you wanna show for example the customised context menu 
    // myContextMenu();
    return false;
}, false);

Не забудьте вернуть false, иначе стандартное контекстное меню все равно будет всплывать.

вам не нужен return false, просто preventDefault

charlietfl 26.05.2018 01:52

@mooga, спасибо, но как это решение может обрабатывать меню как родное (например, если вы нажмете где-нибудь на странице, меню может скрыться)

Kuan 26.05.2018 02:20

Есть несколько действий, закрывающих собственное контекстное меню:

  • Щелкните снаружи: Слушайте document.onmousedown и, чтобы предотвратить всплытие кликов по другим (действительным) элементам и закрытие контекстного меню, вы должны остановить его распространение в промежуточном обработчике с помощью Event.stopPropagation.

    document.onclick также будет работать, но контекстное меню будет оставаться видимым до тех пор, пока вы не отпустите кнопку мыши, а не исчезнет при нажатии.

    В сенсорных устройствах вы должны прослушивать document.touchstart, поскольку некоторые устройства, такие как iPad, не запускают события click.

  • Нажатие Esc: Прослушайте document.onkeydown и проверьте, является ли нажатая клавиша Esc, проверяя KeyboardEvent.keyCode, KeyboardEvent.which и KeyboardEvent.key.

  • Сменить вкладку / окно: слушать window.onblur.

  • Прокрутка мыши: В Chrome слушайте document.onmousewheel. Посмотрите здесь, чтобы получить подробный ответ о том, как обнаружить колесо мыши в разных браузерах: колесо мыши, колесо и DOMMouseScroll в JavaScript.

    Когда это происходит, собственное контекстное меню закрывается, независимо от того, есть ли на странице прокрутка или нет, по крайней мере, в Chrome в Windows 10.

Вот простой пример с некоторыми из упомянутых мною опций:

const contextMenu = document.getElementById('contextMenu');
const MARGIN = 10;

document.oncontextmenu = (e) => {
  e.preventDefault();
  
  const target = e.target;

  if (contextMenu === target || contextMenu.contains(target)) {
    // A right-click on the context menu itself (or anything inside it) will NOT reposition it:
    return;
  }
  
  contextMenu.style.left = `${ Math.min(window.innerWidth - contextMenu.offsetWidth - MARGIN, Math.max(MARGIN, e.clientX)) }px`;
  contextMenu.style.top = `${ Math.min(window.innerHeight - contextMenu.offsetHeight - MARGIN, Math.max(MARGIN, e.clientY)) }px`;

  contextMenu.classList.remove('hidden');
};

contextMenu.onmousedown = (e) => {
  // We don't want this click to close the context menu, so we stop its propagation:
  e.stopPropagation();
};

// EVENTS THAT CLOSE THE CONTEXT MENU:

window.onblur = () => {
  contextMenu.classList.add('hidden');
};

document.onmousedown = () => {
  contextMenu.classList.add('hidden');
};

document.onmousewheel = () => {
  contextMenu.classList.add('hidden');
};

document.onkeydown = (e) => {
  if (e.key === 'Escape' || e.which === 27 || e.keyCode === 27) {
    contextMenu.classList.add('hidden');
  }
};
html,
body {
  height: 100%;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
  font-family: monospace;
}

#contextMenu {
  box-sizing: border-box;
  padding: 5px;
  width: 200px;
  min-height: 50px;
  max-height: calc(100vh - 20px);
  background: white;
  position: fixed;
  border-radius: 2px;
  box-shadow: 0 0 32px rgba(0, 0, 0, .25);
  transition: box-shadow ease-in 50ms;
}

#contextMenu:hover {
  box-shadow: 0 0 48px rgba(0, 0, 0, .25);
}

#contextMenu:active {
  box-shadow: 0 0 16px rgba(0, 0, 0, .25);
}

#contextMenuImage {
  width: 100%;
  border-radius: 2px;
  display: block;
}

.hidden {
  visibility: hidden;
}
<div id = "contextMenu" class = "hidden">
  <img id = "contextMenuImage" src = "https://media1.giphy.com/media/3o7aTskHEUdgCQAXde/giphy.gif" />
</div>

RIGHT-CLICK TO SEE THE CONTEXT MENU

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

Очень полезно, спасибо. Получил свой голос. Но должен ли keyCode для escape не быть 27 вместо 70?

Bruno Eberhard 30.05.2019 13:06

@BrunoEberhard Да, вы правы, только что исправили ? Спасибо (:

Danziger 30.05.2019 17:04

Другие вопросы по теме