自定义上下文菜单始终可见

问题描述 投票:2回答:2

我正在实现当用户点击鼠标左键时出现的自定义菜单,我无法设置菜单的位置(X,Y),这样无论哪个部分都可以看到整个菜单它打开的页面。

下图显示了问题:

菜单的宽度根据文本的宽度而增加,因此调整其位置和高度也是一个挑战。

var elements = $('#content').find('h1, p, span');

var setMenuPosition = function(x, y) {
  $("#menu").css('top', y);
  $("#menu").css('left', x);
};

var setSelectedText = function() {
  $('#menu').data('text', $(this).text());
};

var openMenu = function(e) {
  e.stopPropagation();
  elements.css('border', '1px solid transparent');
  $(this).css('border', '1px dashed #333');
  $('#menu').addClass('active');
  $('#selected-text').text($('#menu').data('text'));
  setMenuPosition(e.pageX, e.pageY);
};

var closeMenu = function() {
  elements.css('border', '1px solid transparent');
  $('#menu').removeClass('active');
};

$('#content').find('h1, p, span').on('mouseenter', setSelectedText);
$('#content').find('h1, p, span').on("click", openMenu);
$('#menu').on('mouseleave', closeMenu);
h1,
p,
span {
  border: 1px solid transparent;
}

#content {
  background-color: #e9e9ea;
  padding: 25px;
}

#menu {
  visibility: hidden;
  opacity: 0;
  transition: visibility 0s, opacity 0.5s linear;
  background-color: #84ce6a;
  color: #fff;
  padding: 15px;
  position: absolute;
  min-width: 200px;
  border-radius: 8px;
}

#menu.active {
  visibility: visible;
  opacity: 1;
}

#my-span {
  background-color: rgb(255, 79, 79);
  color: rgb(255, 255, 255);
  padding: 0px 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="content">
  <h1>My Title</h1>
  <p>My text</p>
  <p>My another text</p>
  <p>My text <span id="my-span">My span</span>, other part of the same text</p>
</div>

<div id="menu">
  <h4>Selected text is: <span id="selected-text"></span></h4>
  <button>
    Ok
    </button>
</div>

我的小提琴:https://jsfiddle.net/robsonnogueira/295d78ak/

javascript jquery html css css3
2个回答
1
投票

要防止菜单移出视口,您需要以下逻辑:

// 1. Set menu content
$menuContent.text(ev.currentTarget.textContent);

// 2. Get X, Y click coordinates
let X = ev.clientX;
let Y = ev.clientY;

// 3. Fix X, Y
X = Math.max(0, Math.min(X, $win.width() - $menu.outerWidth(true)) );
Y = Math.max(0, Math.min(Y, $win.height() - $menu.outerHeight(true)) );

// 4. Show menu
$menu.css({left:X, top:Y}).addClass('is-visible');

考虑到窗口(视口)大小和菜单大小(插入其内容后) - 并修复,通过使用Math.max()Math.min()的组合相应地修改X,Y坐标

这是一个例子:

jQuery($ => {

  const $win = $(window);
  const $menu = $('#menu');
  const $menuContent = $('#menu-content');
  
  const menuOpen = (ev) => {
    ev.stopPropagation();
    
    // 1. Set menu content
    $menuContent.text(ev.currentTarget.textContent);
  
    // 2. Get X, Y click coordinates
    let X = ev.clientX;
    let Y = ev.clientY;
        
    // 3. Fix X, Y
    X = Math.max(0, Math.min(X, $win.width() - $menu.outerWidth(true)) );
    Y = Math.max(0, Math.min(Y, $win.height() - $menu.outerHeight(true)) );
    
    // 4. Show menu
    $menu.css({left:X, top:Y}).addClass('is-visible');
  }
  
  const menuClose = () => {
    $menu.removeClass('is-visible');
  }

  // Events
  $(".menu-open").on('click', menuOpen);
  $(".menu-close").on('click', menuClose);
  $(document).on('click', menuClose);
  $menu.on('click', ev => ev.stopPropagation());

});
html, body {
  height: 100%;
  margin:0;
  font: 14px/1.4 sans-serif;
}

#menu {
  position: fixed;
  max-width: 300px;
  left: 0;
  top: 0;
  background: #84ce6a;
  padding: 10px 20px;
  visibility: hidden;
  opacity: 0;
  transition: visibility 0.24s, opacity 0.24s;
}

#menu.is-visible {
  visibility: visible;
  opacity: 1;
}

/*Demo only*/
.menu-open{
  position: absolute;
}
.menu-open:nth-child(1) {top: 0; left: 0;}
.menu-open:nth-child(2) {top: 0; right: 0;}
.menu-open:nth-child(3) {bottom: 0; left: 0;}
.menu-open:nth-child(4) {bottom: 0; right: 0;}
<span class="menu-open">Click to open menu</span>
<span class="menu-open">Click me</span>
<span class="menu-open">Click here to open menu</span>
<span class="menu-open">Click to open menu</span>

<div id="menu">
  <h3>This is my menu</h3>
  <div id="menu-content"></div>
  <button class="menu-close">CLOSE MENU</button>
</div>

<script src="//code.jquery.com/jquery-3.3.1.min.js"></script>

以上可以通过以下方式进一步改进:

  • 使菜单在“右侧”同样在左侧执行 - 首先计算点翻转是否可实现(将元素固定在相对的右上角,右下角或左下角),或者 - 像现在一样到达边缘。
  • 修复菜单宽度/高度(如果不适合视口)(可能需要一些额外的CSS用于菜单内容/正文滚动条)

-1
投票

罗布森,有几件事需要考虑。但主要是你似乎希望弹出窗口或模态出现在同一个位置,为它提供最大的透视文本空间。我更新了代码以更改一些CSS和JS。基本上,您只想在用户点击或计时器用完时打开和关闭“活动”类。此外,您希望弹出/模态的位置正确,这意味着它一直保留,因为它为文本提供了最大的空间。或者,可能需要进行包装,您可以在其中设置模态/弹出窗口的最大宽度,将其限制为适当的尺寸。

JavaScript:这里我刚刚添加了一个jQuery调用,因为你正在使用它来切换活动类并注释掉你设置的直接CSS值。

CSS:我将'visibility'更改为'display',因为它将它从文档流中取出。基本上可见性:隐藏仍然在流中具有div并且即使它不是“可见的”也会影响对齐。另一方面,显示器将其从流动中移除,因此不会影响对齐。我使用的值是'display:none'表示不可见,'display:block'表示它,因为它是一个块元素。调查其他影响的其他值。

var elements = $('#content').find('h1, p, span');

var setMenuPosition = function(x, y) {
  var m = $('#content');
  $("menu").toggleClass('active');
  //$("#menu").css('top', y);
  //$("#menu").css('left', x);
};

var setSelectedText = function() {
  $('#menu').data('text', $(this).text());
};

var openMenu = function(e) {
  e.stopPropagation();
  elements.css('border', '1px solid transparent');
  $(this).css('border', '1px dashed #333');
  $('#menu').addClass('active');
  $('#selected-text').text($('#menu').data('text'));
  setMenuPosition(e.pageX, e.pageY);
};

var closeMenu = function() {
  elements.css('border', '1px solid transparent');
  $('#menu').removeClass('active');
};

$('#content').find('h1, p, span').on('mouseenter', setSelectedText);
$('#content').find('h1, p, span').on("click", openMenu);
$('#menu').on('mouseleave', closeMenu);
h1,
	p,
	span {
	  border: 1px solid transparent;
	}

	#content {
	  background-color: #e9e9ea;
	  padding: 25px;
	}

	#menu {
	  /*visibility: hidden;*/
	  display:none;
	  opacity: 0;
	  transition: visibility 0s, opacity 0.5s linear;
	  background-color: #84ce6a;
	  color: #fff;
	  padding: 15px;
	  /*position: absolute;*/
	  position:relative;
	  top:0;
	  left:0;
	  min-width: 200px;
	  border-radius: 8px;
	}

	#menu.active {
	  /*visibility: visible;*/
	  display:block;
	  opacity: 1;
	}

	#my-span {
	  background-color: rgb(255, 79, 79);
	  color: rgb(255, 255, 255);
	  padding: 0px 5px;
	}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="content">
  <h1>My Title</h1>
  <p>My text</p>
  <p>My another text</p>
  <p>My text <span id="my-span">My span</span>, other part of the same text</p>
</div>

<div id="menu">
  <h4>Selected text is: <span id="selected-text"></span></h4>
  <button>
    Ok
    </button>
</div>
© www.soinside.com 2019 - 2024. All rights reserved.