我正在实现一个自定义菜单,当用户单击鼠标左键时会出现该菜单,并且尝试设置菜单的位置(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>
答案 0 :(得分: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');
考虑了窗口( viewport )的大小和菜单的大小(插入其内容之后)-并通过结合{{1 }}和Math.max()
以下是一个示例:
Math.min()
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;}
以上内容可以通过以下方式进一步改进:
答案 1 :(得分:-1)
罗布森,有几件事情要考虑。但主要是您似乎希望弹出窗口或模式出现在同一位置,从而为显示文本提供最大的空间。我更新了代码以更改一些CSS和JS。本质上,您只想在用户单击或计时器用尽时打开和关闭“活动”类。另外,您还希望弹出窗口/模式的位置正确,这意味着一直到最左侧,因为它为文本提供了最大的空间。或者,可能需要包装,其中您可以将模式/弹出窗口的最大宽度设置为适当的尺寸。
JavaScript:在这里,我刚刚添加了一个jQuery调用,因为您使用它来切换活动类并注释掉了您设置的直接CSS值。
CSS:我将“可见性”更改为“显示”,因为它使它脱离了文档流。基本上是可见性:即使它不是“可见的”,隐藏的流中仍具有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>