javascript - 防止菜单显示在窗口外

标签 javascript jquery html css

我在 php 文件列表应用程序中使用 ul 作为上下文菜单。

我最近添加了这段代码,当光标离窗口边界太近时移动菜单,以防止菜单部分绘制在窗口之外。

if ((PosY + elm.outerHeight()) > $(window).height()) {
  PosY = PosY - elm.outerHeight();
}
if ((PosX + elm.outerWidth()) > $(window).width()) {
  PosX = PosX - elm.outerWidth();
}

但是……
有时代码有效,菜单被移动,
而且有时不起作用,菜单显示如下:
(假设它不像 5 次中的 1 次那样工作)

Menu is outside !

我试着安慰变量,但它们似乎是正确的,我真的不明白为什么会这样。

这是一个工作片段,我设法重现了这个问题。
(因为它是我的代码的摘录,所以缺少大部分 CSS,但这并不重要。)

// Global vars
var PosX = 0;
var PosY = 0;

// Mouse mouve
$(document).mousemove(function(e) {
  PosX = e.pageX;
  PosY = e.pageY;
  return;
});

/*
	CONTEXT MENU
*/
// Trigger action when the contexmenu is about to be shown
$(document).on("contextmenu", function(event) {
  // Avoid the regular one
  event.preventDefault();
});
// If the document is clicked somewhere
$(document).on("mousedown", function(e) {
  // If the clicked element is not the menu
  if ($(e.target).parents(".ContextMenu").length == 0) {
    // Hide it
    $(".ContextMenu").fadeOut(100);
  }
});

// On context menu…
function ContextMenu(id) {

  elm = $("#" + id);

  /*
  console.log("PosY:", PosY);
  console.log("elm H:", elm.outerHeight());
  console.log("win H:", $(window).height());
	
  console.log("PosX:", PosX);
  console.log("elm W:", elm.outerWidth());
  console.log("win W:", $(window).width());
  */

  // Moves menu if out of screen
  if ((PosY + elm.outerHeight()) > $(window).height()) {
    PosY = PosY - elm.outerHeight();
  }
  if ((PosX + elm.outerWidth()) > $(window).width()) {
    PosX = PosX - elm.outerWidth();
  }

  // Hide and reopen the menu required
  elm.fadeOut(100, function() {
    elm.css({
      "top": PosY,
      "left": PosX
    }).fadeIn(200);
  });
  //console.log("Context menu on: " + elm);
  return false;
}
@charset "UTF-8";

* {
  margin: 0;
  padding: 0;
}

body {
  font-size: 16px;
  position: fixed;
  color: #000;
}

p,
input,
label,
button,
a {
  font-family: "Source Sans Pro", "Trebuchet MS", Helvetica, sans-serif;
  display: inline-block;
  cursor: inherit;
}

#InTable {
  table-layout: fixed;
  width: 100%;
  border: 0;
  border-collapse: collapse;
  margin-bottom: 800px;
}


/*	Scrollbar	*/

#Table::-webkit-scrollbar-track-piece {
  background-color: #DDD;
}

#Table::-webkit-scrollbar-thumb {
  background-color: #000;
}

thead th {
  padding: 4px 0;
}

thead th i {
  margin-left: 4px;
  font-size: 14px !important;
  color: #CCC;
}

thead th,
tbody tr {
  cursor: pointer;
}

tbody td {
  vertical-align: middle;
}

tbody td:first-of-type {
  margin: 0 auto;
  /*overflow: hidden;	*/
}

tbody td img {
  vertical-align: middle;
  height: 32px;
}

tbody tr:nth-of-type(odd) td {
  background-color: #EEEEEE;
}

tbody tr:nth-of-type(even) td {
  background-color: #DDDDDD;
}

#Table th,
#Table td {
  position: relative;
}

#Table p {
  padding-left: 4px;
}

.ContextMenu {
  position: fixed;
  display: none;
  background: #f8f8f8;
  border: 2px solid #888;
  z-index: 2;
  color: #333;
  /* Smoothy color */
}

.ContextMenu div {
  background: #e8e8e8;
  height: 16px;
  padding: 4px;
  border-bottom: 1px solid #CCC;
}

.ContextMenu div:not(:first-child) {
  border-top: 2px solid #AAA;
}

.ContextMenu li {
  display: block;
  height: 20px;
  padding: 6px 24px 6px 8px;
  cursor: pointer;
  list-style-type: none;
  transition: all .3s ease;
  white-space: nowrap;
}

.ContextMenu img,
.ContextMenu i,
.ContextMenu span,
.ContextMenu p {
  display: inline-block;
  height: 20px;
  vertical-align: middle;
}

.ContextMenu img,
.ContextMenu i,
.ContextMenu span {
  width: 20px;
  text-align: center;
  margin-right: 8px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<style media="" data-href="https://use.fontawesome.com/releases/v5.0.6/css/all.css"></style>

<body class="tblr0 bg" id="DropBox" contenttype="text/html; charset=UTF-8" onload="" onresize="">
  <div class="abs t40blr0" id="Content" style="top: 100px;">
    <div class="abs tblr0 overflow-x-hidden overflow-y-auto" id="Table" style="opacity: 1;">
      <table class="tblr0" id="InTable">
        <thead class="bg-silver align-l">
          <tr style="width: 100%;">
            <th data-sort="int" id="Icos" style="width: 68px; min-width: 68px; max-width: 68px;"><p>Icon</p><i class="fa fa-sort"></i></th>
            <th data-sort="string" id="Name" style="width: 291.333px;">
              <p>Filename</p><i class="fa fa-sort"></i></th>
            <th data-sort="string" id="Type" style="width: 218.5px;">
              <p>Type</p><i class="fa fa-sort"></i></th>
          </tr>
        </thead>
        <tbody>
          <tr onclick="" oncontextmenu="ContextMenu('ContextMenu0');" style="width: 100%;">
            <td data-sort-value="0" style="height: 64px;">
              <div class="Icons" style="line-height: 64px; font-size: 60px;"></div>
            </td>
            <td style="height: 64px;">
              <div class="Name">
                <p>.&nbsp;&nbsp;&nbsp;<i>[Current]</i></p>
              </div>
            </td>
            <td style="height: 64px;">
              <p>&lt; Current Directory&nbsp;&gt;</p>
            </td>
            <td style="height: 64px;">
              <ul class="ContextMenu" id="ContextMenu0">
                <div onclick="context_menu_close(event);">
                  <p>Tools</p>
                </div>
                <li onclick=""><i class="fa fa-folder"></i>
                  <p>Create new Folder</p>
                </li>
                <li onclick=""><i class="fa fa-file"></i>
                  <p>Create new File</p>
                </li>
                <li onclick=""><i class="fa fa-upload"></i>
                  <p>Upload files in current folder</p>
                </li>
                <li onclick=""><i class="fa fa-download"></i>
                  <p>Download current folder as Zip</p>
                </li>
              </ul>
            </td>
          </tr>
          <tr onclick="" oncontextmenu="ContextMenu('ContextMenu1');" style="width: 100%;">
            <td data-sort-value="1" style="height: 64px;">
              <div class="Icons" style="line-height: 64px; font-size: 60px;"></div>
            </td>
            <td style="height: 64px;">
              <div class="Name pr4">
                <p>Acces<span class="opac06">&nbsp;</span></p>
              </div>
            </td>
            <td style="height: 64px;">
              <p>&lt;&nbsp;Directory&nbsp;&gt;</p>
            </td>
            <td style="height: 64px;">
              <ul class="ContextMenu" id="ContextMenu1" style="top: 218px; left: 854.625px; display: none;">
                <div onclick="context_menu_close(event);">
                  <p>Tools</p>
                </div>
                <li onclick=""><i class="fa fa-i-cursor"></i>
                  <p>Rename</p>
                </li>
                <li onclick=""><i class="far fa-arrow-alt-circle-right"></i>
                  <p>Move</p>
                </li>
                <li onclick=""><i class="far fa-copy"></i>
                  <p>Copy</p>
                </li>
                <li onclick=""><i class="far fa-trash-alt"></i>
                  <p>Delete</p>
                </li>
                <li onclick=""><i class="fa fa-download"></i>
                  <p>Download folder as Zip</p>
                </li>
              </ul>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</body>

谁能教教我?
我的代码有什么问题?
提前致谢。

最佳答案

我认为问题在于 .fadeOut(100).fadeIn(200)。这些是动画,因此,它们相对于其余代码异步运行。

老实说,我没有资格向您详细解释为什么以及如何在您的代码中发生这种情况。基本上:更新 posXposY 的过程以及隐藏显示的过程 菜单 重叠。请注意,按原样使用您的代码,如果您在每次点击之间花时间(~1 秒),问题永远不会发生,而如果您开始反复点击它,它会越来越频繁地中断,这只是另一个暗示动画的时间是来源的问题。

解决方案:将更新posXposY 放在隐藏显示 菜单。特别是在隐藏菜单之后、再次显示菜单之前的回调中。

如果小妖精重现,请告诉我!

// Global vars
var PosX = 0;
var PosY = 0;

// Mouse mouve
$(document).mousemove(function(e) {
  PosX = e.pageX;
  PosY = e.pageY;
  return;
});

/*
	CONTEXT MENU
*/
// Trigger action when the contexmenu is about to be shown
$(document).bind("contextmenu", function(event) {
  // Avoid the regular one
  event.preventDefault();
});
// If the document is clicked somewhere
$(document).bind("mousedown", function(e) {
  // If the clicked element is not the menu
  if ($(e.target).parents(".ContextMenu").length == 0) {
    // Hide it
    $(".ContextMenu").fadeOut(100);
  }
});

// On context menu…
function ContextMenu(id) {

  elm = $("#" + id);

  /*
  console.log("PosY:", PosY);
  console.log("elm H:", elm.outerHeight());
  console.log("win H:", $(window).height());
	
  console.log("PosX:", PosX);
  console.log("elm W:", elm.outerWidth());
  console.log("win W:", $(window).width());
  */

// Hide and reopen the menu required
elm.fadeOut(100, function() {
  // Moves menu if out of screen
  if ((PosY + elm.outerHeight()) > $(window).height()) {
    PosY = PosY - elm.outerHeight();
  }
  if ((PosX + elm.outerWidth()) > $(window).width()) {
    PosX = PosX - elm.outerWidth();
  }
    elm.css({
      "top": PosY,
      "left": PosX
    }).fadeIn(200);
  });
  return false;
}
@charset "UTF-8";

* {
  margin: 0;
  padding: 0;
}

body {
  font-size: 16px;
  position: fixed;
  color: #000;
}

p,
input,
label,
button,
a {
  font-family: "Source Sans Pro", "Trebuchet MS", Helvetica, sans-serif;
  display: inline-block;
  cursor: inherit;
}

#InTable {
  table-layout: fixed;
  width: 100%;
  border: 0;
  border-collapse: collapse;
  margin-bottom: 800px;
}


/*	Scrollbar	*/

#Table::-webkit-scrollbar-track-piece {
  background-color: #DDD;
}

#Table::-webkit-scrollbar-thumb {
  background-color: #000;
}

thead th {
  padding: 4px 0;
}

thead th i {
  margin-left: 4px;
  font-size: 14px !important;
  color: #CCC;
}

thead th,
tbody tr {
  cursor: pointer;
}

tbody td {
  vertical-align: middle;
}

tbody td:first-of-type {
  margin: 0 auto;
  /*overflow: hidden;	*/
}

tbody td img {
  vertical-align: middle;
  height: 32px;
}

tbody tr:nth-of-type(odd) td {
  background-color: #EEEEEE;
}

tbody tr:nth-of-type(even) td {
  background-color: #DDDDDD;
}

#Table th,
#Table td {
  position: relative;
}

#Table p {
  padding-left: 4px;
}

.ContextMenu {
  position: fixed;
  display: none;
  background: #f8f8f8;
  border: 2px solid #888;
  z-index: 2;
  color: #333;
  /* Smoothy color */
}

.ContextMenu div {
  background: #e8e8e8;
  height: 16px;
  padding: 4px;
  border-bottom: 1px solid #CCC;
}

.ContextMenu div:not(:first-child) {
  border-top: 2px solid #AAA;
}

.ContextMenu li {
  display: block;
  height: 20px;
  padding: 6px 24px 6px 8px;
  cursor: pointer;
  list-style-type: none;
  transition: all .3s ease;
  white-space: nowrap;
}

.ContextMenu img,
.ContextMenu i,
.ContextMenu span,
.ContextMenu p {
  display: inline-block;
  height: 20px;
  vertical-align: middle;
}

.ContextMenu img,
.ContextMenu i,
.ContextMenu span {
  width: 20px;
  text-align: center;
  margin-right: 8px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<style media="" data-href="https://use.fontawesome.com/releases/v5.0.6/css/all.css"></style>

<body class="tblr0 bg" id="DropBox" contenttype="text/html; charset=UTF-8" onload="" onresize="">
  <div class="abs t40blr0" id="Content" style="top: 100px;">
    <div class="abs tblr0 overflow-x-hidden overflow-y-auto" id="Table" style="opacity: 1;">
      <table class="tblr0" id="InTable">
        <thead class="bg-silver align-l">
          <tr style="width: 100%;">
            <th data-sort="int" id="Icos" style="width: 68px; min-width: 68px; max-width: 68px;"><p>Icon</p><i class="fa fa-sort"></i></th>
            <th data-sort="string" id="Name" style="width: 291.333px;">
              <p>Filename</p><i class="fa fa-sort"></i></th>
            <th data-sort="string" id="Type" style="width: 218.5px;">
              <p>Type</p><i class="fa fa-sort"></i></th>
          </tr>
        </thead>
        <tbody>
          <tr onclick="" oncontextmenu="ContextMenu('ContextMenu0');" style="width: 100%;">
            <td data-sort-value="0" style="height: 64px;">
              <div class="Icons" style="line-height: 64px; font-size: 60px;"></div>
            </td>
            <td style="height: 64px;">
              <div class="Name">
                <p>.&nbsp;&nbsp;&nbsp;<i>[Current]</i></p>
              </div>
            </td>
            <td style="height: 64px;">
              <p>&lt; Current Directory&nbsp;&gt;</p>
            </td>
            <td style="height: 64px;">
              <ul class="ContextMenu" id="ContextMenu0">
                <div onclick="context_menu_close(event);">
                  <p>Tools</p>
                </div>
                <li onclick=""><i class="fa fa-folder"></i>
                  <p>Create new Folder</p>
                </li>
                <li onclick=""><i class="fa fa-file"></i>
                  <p>Create new File</p>
                </li>
                <li onclick=""><i class="fa fa-upload"></i>
                  <p>Upload files in current folder</p>
                </li>
                <li onclick=""><i class="fa fa-download"></i>
                  <p>Download current folder as Zip</p>
                </li>
              </ul>
            </td>
          </tr>
          <tr onclick="" oncontextmenu="ContextMenu('ContextMenu1');" style="width: 100%;">
            <td data-sort-value="1" style="height: 64px;">
              <div class="Icons" style="line-height: 64px; font-size: 60px;"></div>
            </td>
            <td style="height: 64px;">
              <div class="Name pr4">
                <p>Acces<span class="opac06">&nbsp;</span></p>
              </div>
            </td>
            <td style="height: 64px;">
              <p>&lt;&nbsp;Directory&nbsp;&gt;</p>
            </td>
            <td style="height: 64px;">
              <ul class="ContextMenu" id="ContextMenu1" style="top: 218px; left: 854.625px; display: none;">
                <div onclick="context_menu_close(event);">
                  <p>Tools</p>
                </div>
                <li onclick=""><i class="fa fa-i-cursor"></i>
                  <p>Rename</p>
                </li>
                <li onclick=""><i class="far fa-arrow-alt-circle-right"></i>
                  <p>Move</p>
                </li>
                <li onclick=""><i class="far fa-copy"></i>
                  <p>Copy</p>
                </li>
                <li onclick=""><i class="far fa-trash-alt"></i>
                  <p>Delete</p>
                </li>
                <li onclick=""><i class="fa fa-download"></i>
                  <p>Download folder as Zip</p>
                </li>
              </ul>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</body>

关于javascript - 防止菜单显示在窗口外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49385822/

相关文章:

javascript - IE9 - 使用 jQuery 将 html 表加载到页面中

javascript - 不适用于循环

javascript - jQuery UI 仅在特殊区域删除元素

javascript - 无法在谷歌地图中保存多边形

javascript - 加载后跳转到 iframe

jQuery - 函数后跟同一事件中的 if 条件

javascript - Odoo 数据透视报告错误值被转换为 "Undefined"

javascript - jQuery UI 日期选择器 : how to set container's display to flex?

javascript - 访问选项值 webdriver.io

php - WordPress : How to make tablesort work with Genesis