首页 > 解决方案 > 阻止上下文菜单在页面右侧被剪切

问题描述

当我右键单击页面的右侧部分时,我有一个上下文菜单被剪切,如下所示:

菜单在页面边缘被剪切,所以我希望菜单像在 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: default;
}

.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>

标签: javascripthtmlcsscontextmenu

解决方案


这应该可以通过简单的比较来实现。在您设置上下文菜单 ( 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的上下文菜单宽度 ( ) 距离内。如果是这样,我们将左侧位置设置为当前光标位置减去宽度。contextMenuWidthwindow.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>


推荐阅读