Javascript 检测下拉式导航是否会离开屏幕并重新定位
我有您典型的下拉式导航,我正在努力确保下拉菜单链接始终可访问且可见:Javascript 检测下拉式导航是否会离开屏幕并重新定位,javascript,jquery,html,css,Javascript,Jquery,Html,Css,我有您典型的下拉式导航,我正在努力确保下拉菜单链接始终可访问且可见: <li><a href="#">Link 1</a> <ul> <li><a href="#">Link 1</a></li> <li><a href="#">Link 2</a></li> <li><a hre
<li><a href="#">Link 1</a>
<ul>
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
</ul>
</li>
<li><a href="#">Link 2</a>
<ul>
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
</ul>
</li>
<!-- etc. -->
</ul>
存在未知数量的顶级链接(它们是由用户创建的)。我遇到的问题是,如果顶层链接离右边太远,有时下拉菜单(向右)会离开屏幕。我添加了这一点CSS来补偿:
.dropdown > li:last-child ul { /* ...or use a class on the last link for IE */
right:0;
}
现在,最后一个将转到左侧,而不是屏幕外,这很好,但有几个问题:
类
名称或其他内容,以便我可以使用CSS将其保留在屏幕上
我可能会使用的一个线索是,如果菜单离开屏幕,它总是在窗口底部产生一个垂直滚动条,但我不知道如何使用这些知识。我尝试了关于检测垂直滚动条的公认答案,但出于某种原因,它总是返回true
,并且总是添加“edge”类(可能时间有问题?)
使用javascript进行演示:
真的,我不想看到一个垂直的滚动条,即使是在一瞬间,所以我不确定这是一种方式去,加上可能有误报(滚动条的其他原因)
我也尝试过这个解决方案,我承认,我不太明白,也无法让它发挥作用:
$(“.dropdown li”).on('mouseenter mouseleave',函数(e){
var elm=$('ul:first',this);
var off=elm.offset();
var t=关闭顶部;
var l=关闭。左侧;
var h=榆树高度();
var w=榆树宽度();
var docH=$(窗口).height();
var docW=$(window.width();
var isEntirelyVisible=(t>0&&l>0&&t+h
我假设解决方案需要javascript,我使用的是jQuery,但我不知道如何解决这个问题。有什么想法吗?我想你就快到了 你应该只对宽度的计算感兴趣。如果下拉元素的宽度和该元素的偏移量大于容器的宽度,则需要切换菜单
$(function () {
$(".dropdown li").on('mouseenter mouseleave', function (e) {
if ($('ul', this).length) {
var elm = $('ul:first', this);
var off = elm.offset();
var l = off.left;
var w = elm.width();
var docH = $(".container").height();
var docW = $(".container").width();
var isEntirelyVisible = (l + w <= docW);
if (!isEntirelyVisible) {
$(this).addClass('edge');
} else {
$(this).removeClass('edge');
}
}
});
});
$(函数(){
$(“.dropdown li”).on('mouseenter mouseleave',函数(e){
如果($('ul',此).length){
var elm=$('ul:first',this);
var off=elm.offset();
var l=关闭。左侧;
var w=榆树宽度();
var docH=$(“.container”).height();
var docW=$(“.container”).width();
var isEntrelyVisible=(l+w这里有一个函数,可用于向右或向下弹出的菜单(基于@r0m4n的代码):
函数固定弹出按钮(containerElement、parentElement、flyoutElement、flyoutDirection){
$(parentElement).on('mouseenter mouseleave',函数(e){
var元素=$(flyoteElement,this);
var offset=element.offset();
开关(弹出方向){
案例“关闭”:
var top=offset.top;
var height=element.height();
var windowHeight=$(containerElement).height();
var IsEntireyVisible=(顶部+高度我无法使addClass(“edge”)正常工作,但我能够修改相关元素的CSS以实现该行为。(仅从r0m4n略微修改):
这可能会有帮助。我会看一看并更新我的结果,谢谢。再想一想,“滚动条检测”方法不是很好,如果它起作用可能会导致误报(滚动条出于另一个原因)。类似这样的东西?是的,非常类似这样的东西,除了在顶层下拉菜单上,还有可堆叠的导航项目(如果视口很小)。我会看看我是否能把这些代码拆开并找到有用的东西,谢谢你理解我的问题。@WesleyMurch-它有点旧。不久前写了它,但最终没有使用它。我确信有足够的空间进行更新和改进。希望它能帮上忙。你搞定了!我的大部分想法都是在我实际发布问题之前产生的(当然),我的大脑被它炸得焦头烂额,我没有意识到我的错误。我衷心感谢你,这段代码肯定会在工具箱中。这似乎给出了一个错误“Uncaught TypeError:无法读取未定义的“left”属性”即使是在你的JSFIDLE中。有人知道如何解决这个问题吗?@Aaron啊,是的,很好的捕获…请参阅更新。错误是由于处理程序试图在子嵌套项不存在时重新定位子嵌套项造成的!您好@r0m4n谢谢您的出色回答。但是我有一个小问题,我想在第二级中使用,但它不起作用。@r0m4n这是否可以工作是否有多级下拉列表?我有一个两级的下拉列表,需要能够将第二个列表从第一个列表中偏移。您是否能够添加一个小提琴来显示正在使用该列表?我希望能够将嵌套列表放在嵌套列表中,以便将右侧或左侧的多级下拉列表显示为键入错误“right”变量IsEntrelyVisible应为left+width,是吗?
$(".dropdown li").on('mouseenter mouseleave', function (e) {
// Get the computed style of the body element
var cStyle = document.body.currentStyle||window.getComputedStyle(document.body, "");
// Check the overflow and overflowY properties for "auto" and "visible" values
hasVScroll = cStyle.overflow == "visible"
|| cStyle.overflowY == "visible"
|| (hasVScroll && cStyle.overflow == "auto")
|| (hasVScroll && cStyle.overflowY == "auto");
if (hasVScroll) {
$(this).addClass('edge');
} else {
$(this).removeClass('edge');
}
});
$(".dropdown li").on('mouseenter mouseleave', function (e) {
var elm = $('ul:first', this);
var off = elm .offset();
var t = off.top;
var l = off.left;
var h = elm.height();
var w = elm.width();
var docH = $(window).height();
var docW = $(window).width();
var isEntirelyVisible = (t > 0 && l > 0 && t + h < docH && l+ w < docW);
if ( ! isEntirelyVisible ) {
$(this).addClass('edge');
} else {
$(this).removeClass('edge');
}
});
$(function () {
$(".dropdown li").on('mouseenter mouseleave', function (e) {
if ($('ul', this).length) {
var elm = $('ul:first', this);
var off = elm.offset();
var l = off.left;
var w = elm.width();
var docH = $(".container").height();
var docW = $(".container").width();
var isEntirelyVisible = (l + w <= docW);
if (!isEntirelyVisible) {
$(this).addClass('edge');
} else {
$(this).removeClass('edge');
}
}
});
});
function fixFlyout (containerElement, parentElement,flyoutElement,flyoutDirection) {
$(parentElement).on('mouseenter mouseleave', function (e) {
var element = $(flyoutElement, this);
var offset = element .offset();
switch(flyoutDirection) {
case 'down':
var top = offset.top;
var height = element.height();
var windowHeight = $(containerElement).height();
var isEntirelyVisible = (top + height <= windowHeight);
break;
case 'right':
var left = offset.left;
var width = element.width();
var windowWidth = $(containerElement).width();
var isEntirelyVisible = (top + width <= windowWidth);
break;
}
if (!isEntirelyVisible ) {
$(element).addClass('edge');
} else {
$(element).removeClass('edge');
}
});
}
//Level 1 Flyout
fixFlyout(containerElement = '.header',parentElement = '.header .navigation>.menu>.expanded',flyoutElement = '.menu:first',flyoutDirection = 'down');
//Align submenu to right if cut-off from window
$(function () {
$(".dropdown").on('mouseenter mouseleave', function (e) {
if ($('.dropdown-content', this).length) {
var dropdownElement = $('.dropdown-content:first', this);
var elementOffset = dropdownElement.offset();
var elementOffsetLeft = elementOffset.left;
var elementWidth = dropdownElement.width();
var pageHeigth = $(".show-on-scroll-wrapper").height();
var pageWidth = $(".show-on-scroll-wrapper").width();
//if left offset + width of dropdown is bigger than container width then it is cut-off
if ((elementOffsetLeft + elementWidth) > pageWidth) {
//Align Right
$(".dropdown-content").css({ "left":"auto", "right":"0", "margin-right":"-10px;"});
} else {
//Align Left
$(".dropdown-content").css({ "left":"0", "right":"auto", "margin-left": "-10px;" });
}
}
});
});