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

#javascript #html #css #contextmenu

Вопрос:

У меня есть контекстное меню, которое обрезается, когда я щелкаю правой кнопкой мыши в правой части страницы, как показано здесь:

Меню обрезается по краю страницы, поэтому я хочу, чтобы меню переместилось на другую сторону курсора, как это делается в Chrome или других популярных приложениях. Я попытался посетить другие страницы в StackOverflow и попробовать некоторые демо-версии, но все они говорят об одном и том же, как показано выше. Я также попытался прокомментировать некоторые другие сообщения, посмотрев, ответят ли они, но все равно ничего.

Обновить

Код:

 var menu = document.querySelector('.menu');

function showMenu(x, y) {
  menu.style.left = x   'px';
  menu.style.top = y   'px';
  menu.classList.add('menu-show');
}

function hideMenu() {
  menu.classList.remove('menu-show');
}

function onContextMenu(e) {
  e.preventDefault();
  showMenu(e.pageX, e.pageY);
  document.addEventListener('mousedown', onMouseDown, false);
}

function onMouseDown(e) {
  hideMenu();
  document.removeEventListener('mousedown', onMouseDown);
}

document.addEventListener('contextmenu', onContextMenu, false); 
 /* Page */

html {
  width: 100%;
  height: 100%;
  background: radial-gradient(circle, #fff 0%, #a6b9c1 100%) no-repeat;
}

.container {
  position: absolute;
  top: 20%;
  left: 0;
  width: 100%;
  margin: auto;
  text-align: center;
}

h1,
h2 {
  color: #555;
}


/* Menu */

.menu {
  position: absolute;
  width: 200px;
  padding: 2px;
  margin: 0;
  border: 1px solid #bbb;
  background: #eee;
  background: linear-gradient(to bottom, #fff 0%, #e5e5e5 100px, #e5e5e5 100%);
  z-index: 100;
  border-radius: 3px;
  box-shadow: 1px 1px 4px rgba(0, 0, 0, .2);
  opacity: 0;
  transform: translate(0, 15px) scale(.95);
  transition: transform 0.1s ease-out, opacity 0.1s ease-out;
  pointer-events: none;
}

.menu-item {
  display: block;
  position: relative;
  margin: 0;
  padding: 0;
  white-space: nowrap;
}

.menu-btn {
  display: block;
  color: #444;
  font-family: 'Roboto', sans-serif;
  font-size: 13px;
  cursor: pointer;
  border: 1px solid transparent;
  white-space: nowrap;
  padding: 6px 8px;
  border-radius: 3px;
}

button.menu-btn {
  background: none;
  line-height: normal;
  overflow: visible;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  width: 100%;
  text-align: left;
}

a.menu-btn {
  outline: 0 none;
  text-decoration: none;
}

.menu-text {
  margin-left: 25px;
}

.menu-btn .fa {
  position: absolute;
  left: 8px;
  top: 50%;
  transform: translateY(-50%);
}

.menu-item:hover>.menu-btn {
  color: #fff;
  outline: none;
  background-color: #2E3940;
  background: linear-gradient(to bottom, #5D6D79, #2E3940);
  border: 1px solid #2E3940;
}

.menu-item-disabled {
  opacity: .5;
  pointer-events: none;
}

.menu-item-disabled .menu-btn {
  cursor: defau<
}

.menu-separator {
  display: block;
  margin: 7px 5px;
  height: 1px;
  border-bottom: 1px solid #fff;
  background-color: #aaa;
}

.menu-item-submenu::after {
  content: "";
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  border: 5px solid transparent;
  border-left-color: #808080;
}

.menu-item-submenu:hover::after {
  border-left-color: #fff;
}

.menu .menu {
  top: 4px;
  left: 99%;
}

.menu-show,
.menu-item:hover>.menu {
  opacity: 1;
  transform: translate(0, 0) scale(1);
  pointer-events: auto;
}

.menu-item:hover>.menu {
  transition-delay: 300ms;
} 
 <ul class="menu">
  <li class="menu-item">
    <a href="#" class="menu-btn">
      <i class="fa fa-folder-open"></i>
      <span class="menu-text">Open</span>
    </a>
  </li>
  <li class="menu-item menu-item-disabled">
    <button type="button" class="menu-btn">
            <span class="menu-text">Open in New Window</span>
        </button>
  </li>
  <li class="menu-separator"></li>
  <li class="menu-item">
    <button type="button" class="menu-btn">
            <i class="fa fa-reply"></i>
            <span class="menu-text">Reply</span>
        </button>
  </li>
  <li class="menu-item">
    <button type="button" class="menu-btn">
            <i class="fa fa-star"></i>
            <span class="menu-text">Favorite</span>
        </button>
  </li>
  <li class="menu-item menu-item-submenu">
    <button type="button" class="menu-btn">
            <i class="fa fa-users"></i>
            <span class="menu-text">Social</span>
        </button>
    <ul class="menu">
      <li class="menu-item">
        <button type="button" class="menu-btn">
                    <i class="fa fa-comment"></i>
                    <span class="menu-text">Comment</span>
                </button>
      </li>
      <li class="menu-item menu-item-submenu">
        <button type="button" class="menu-btn">
                    <i class="fa fa-share"></i>
                    <span class="menu-text">Share</span>
                </button>
        <ul class="menu">
          <li class="menu-item">
            <button type="button" class="menu-btn">
                            <i class="fa fa-twitter"></i>
                            <span class="menu-text">Twitter</span>
                        </button>
          </li>
          <li class="menu-item">
            <button type="button" class="menu-btn">
                            <i class="fa fa-facebook-official"></i>
                            <span class="menu-text">Facebook</span>
                        </button>
          </li>
          <li class="menu-item">
            <button type="button" class="menu-btn">
                            <i class="fa fa-google-plus"></i>
                            <span class="menu-text">Google Plus</span>
                        </button>
          </li>
          <li class="menu-item">
            <button type="button" class="menu-btn">
                            <i class="fa fa-envelope"></i>
                            <span class="menu-text">Email</span>
                        </button>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li class="menu-separator"></li>
  <li class="menu-item">
    <button type="button" class="menu-btn">
            <i class="fa fa-download"></i>
            <span class="menu-text">Save</span>
        </button>
  </li>
  <li class="menu-item">
    <button type="button" class="menu-btn">
            <i class="fa fa-edit"></i>
            <span class="menu-text">Rename</span>
        </button>
  </li>
  <li class="menu-item">
    <button type="button" class="menu-btn">
            <i class="fa fa-trash"></i>
            <span class="menu-text">Delete</span>
        </button>
  </li>
</ul>

<div class="container">
  <h1>Context Menu</h1>
  <h2>(right-click anywhere)</h2>
</div> 

Комментарии:

1. Что вы пробовали? Мы ожидаем, что вы проведете некоторое исследование по своей проблеме и попытаетесь сделать это перед публикацией.

2. рассчитайте размер lefting yClient и размер xClient, прежде чем пытаться отобразить контекстное меню. это поможет вам узнать, можете ли вы безопасно визуализировать его, не получая пореза. И чтобы иметь возможность сделать это, вам нужно будет знать точную высоту и ширину вашего пользовательского контекстного меню

3. Нам также нужно будет увидеть ваш код, чтобы иметь возможность помочь вам.

4. Не могли бы вы, пожалуйста, показать нам свой код?

5. Я добавил код и дополнительную информацию.

Ответ №1:

Это должно быть возможно при простом сравнении. Там, где вы задаете положение контекстного меню ( menu.style.left = e.pageX "px"; ), вы можете вместо этого проверить, подойдет ли оно:

   var contextMenuWidth = 250;
  var contextSubMenuWidth = 250;
  var leftPos = ''
  if (e.pageX < window.innerWidth - contextMenuWidth) {
    leftPos = `${e.pageX}px`;
  } else {
    leftPos = `${e.pageX - contextMenuWidth}px`;
  }
  if (e.pageX < window.innerWidth - contextMenuWidth - contextSubMenuWidth) {
    menu.classList.remove("sub-left");
  } else {
    menu.classList.add("sub-left");
  }
  menu.style.left = leftPos;
 

Это проверка того, находится ли положение курсора ( e.pageX ) на расстоянии ширины контекстного меню contextMenuWidth () от правой части экрана ( window.innerWidth ). Если это так, мы устанавливаем левую позицию в текущее положение курсора за вычетом ширины.

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

 .sub-left .menu-sub-list { 
  left: -100%;
  right: 0;
}
 

Это также использует шаблонные литералы для ваших строк CSS, эффективно заменяя numberVariable "px" их:

 `${numberVariable}px`
 

поскольку по возможности лучше избегать использования оператора для объединения строк.

Это применяется в данном примере с жестко заданной шириной контекстного меню, я бы предложил использовать переменную и сохранить ее в соответствующем месте:

 document.onclick = hideMenu;
document.oncontextmenu = rightClick;

function hideMenu() {
  document.getElementById("contextMenu").style.display = "none";
}

function rightClick(e) {
  e.preventDefault();
  var contextMenuWidth = 250;
  var contextSubMenuWidth = 250;
  var menu = document.getElementById("contextMenu")
  menu.style.display = 'block';
  var leftPos = ''
  if (e.pageX < window.innerWidth - contextMenuWidth) {
    leftPos = `${e.pageX}px`;
  } else {
    leftPos = `${e.pageX - contextMenuWidth}px`;
  }
  if (e.pageX < window.innerWidth - contextMenuWidth - contextSubMenuWidth) {
    menu.classList.remove("sub-left");
  } else {
    menu.classList.add("sub-left");
  }
  menu.style.left = leftPos;
  menu.style.top = e.pageY   "px";
}
feather.replace() 
 *,
*:after,
*:before {
  box-sizing: border-box;
}

 :root {
  --color-bg-primary: #d0d6df;
  --color-bg-primary-offset: #f1f3f7;
  --color-bg-secondary: #fff;
  --color-text-primary: #3a3c42;
  --color-text-primary-offset: #898c94;
  --color-orange: #dc9960;
  --color-green: #1eb8b1;
  --color-purple: #657cc4;
  --color-black: var(--color-text-primary);
  --color-red: #d92027;
}

body {
  font-family: "Inter", sans-serif;
  background-color: var(--color-bg-primary);
  color: var(--color-text-primary);
}

.menu {
  background-color: var(--color-bg-secondary);
  border-radius: 10px;
  box-shadow: 0 10px 20px #40404015;
}

.menu-list {
  margin: 0;
  display: block;
  width: 100%;
  padding: 8px;
}

.menu-list .menu-list {
  border-top: 1px solid #ddd;
}

.menu-sub-list:hover {
  display: flex;
}

.menu-sub-list {
  display: none;
  padding: 8px;
  background-color: var(--color-bg-secondary);
  border-radius: 10px;
  box-shadow: 0 10px 20px rgba(#404040, 0.15);
  position: absolute;
  left: 100%;
  right: 0;
  z-index: 100;
  width: 100%;
  top: 0;
  flex-direction: column;
}

.sub-left .menu-sub-list { 
  left: -100%;
  right: 0;
}

.menu-item {
  position: relative;
}

.menu-button:hover {
  background-color: var(--color-bg-primary-offset);
}

.menu-button:hover .menu-sub-list {
  display: flex;
}

.menu-button:hover svg {
  stroke: var(--color-text-primary);
}

.menu-button {
  font: inherit;
  border: 0;
  padding: 8px 8px;
  padding-right: 36px;
  width: 100%;
  border-radius: 8px;
  display: flex;
  align-items: center;
  position: relative;
  background-color: var(--color-bg-secondary);
}

.menu-button--delete:hover {
  color: var(--color-red);
}

svg:first-of-type {
  stroke: var(--color-red);
}

.menu-button--orange svg:first-of-type {
  stroke: var(--color-orange);
}

.menu-button--green svg:first-of-type {
  stroke: var(--color-green);
}

.menu-button--purple svg:first-of-type {
  stroke: var(--color-purple);
}

.menu-button--blacksvg:first-of-type {
  stroke: var(--color-black);
}

.menu-button--checked svg:nth-of-type(2) {
  stroke: var(--color-purple);
}

.menu-button svg {
  width: 20px;
  height: 20px;
  margin-right: 10px;
  stroke: var(--color-text-primary-offset);
}

.menu-button:nth-of-type(2) {
  margin-right: 0;
  position: absolute;
  right: 8px;
}

.container {
  position: absolute;
  width: 250px;
  display: flex;
  align-items: center;
  justify-content: center;
}

ul {
  list-style: none;
} 
 <div class="context-menu">
  <div class="container" id="contextMenu" style="display:none">
    <!-- code here -->
    <div class="menu">
      <ul class="menu-list">
        <li class="menu-item"><button class="menu-button"><i
                                data-feather="corner-up-right"></i>Share</button></li>
        <li class="menu-item"><button class="menu-button"><i data-feather="edit-2"></i>Rename</button></li>
      </ul>
      <ul class="menu-list">
        <li class="menu-item"><button class="menu-button menu-button--black"><i data-feather="circle"></i>No
                            status<i data-feather="chevron-right"></i></button>
          <ul class="menu-sub-list">
            <li class="menu-item"><button class="menu-button menu-button--orange"><i
                                        data-feather="square"></i>Needs review</button></li>
            <li class="menu-item"><button class="menu-button menu-button--purple"><i
                                        data-feather="octagon"></i>In progress</button></li>
            <li class="menu-item"><button class="menu-button menu-button--green"><i
                                        data-feather="triangle"></i>Approved</button></li>
            <li class="menu-item"><button class="menu-button menu-button--black menu-button--checked"><i
                                        data-feather="circle"></i>No status<i data-feather="check"></i></button></li>
          </ul>
        </li>
        <li class="menu-item"><button class="menu-button"><i data-feather="link"></i>Copy Link
                            Address</button></li>
        <li class="menu-item"><button class="menu-button"><i data-feather="folder-plus"></i>Move to</button>
        </li>
        <li class="menu-item"><button class="menu-button"><i data-feather="copy"></i>Copy to</button></li>
        <li class="menu-item"><button class="menu-button"><i data-feather="lock"></i>Make Private</button>
        </li>
        <li class="menu-item"><button class="menu-button"><i data-feather="download"></i>Download</button>
        </li>
      </ul>
      <ul class="menu-list">
        <li class="menu-item"><button class="menu-button menu-button--delete"><i
                                data-feather="trash-2"></i>Delete</button></li>
      </ul>
    </div>
  </div>
</div>
<script src="https://unpkg.com/feather-icons"></script>