javascript – 检测下拉菜单是否会关闭屏幕并重新定位

我有你典型的下拉导航,我想确保下拉菜单链接总是可访问和可见:

<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,
.dropdown li,
.dropdown ul {
    list-style:none;
    margin:0;
    padding:0;
}
.dropdown {
    position:relative;
    z-index:10000;
    float:left;
    width:100%;
}
.dropdown ul {
    position:absolute;
    top:100%;
    visibility:hidden;
    display:none;
    width:16em;
}
.dropdown ul ul {
    top:0;
    left:100%;
}
.dropdown li {
    position:relative;
    float:left;
}
.dropdown li:hover{
    z-index:910;
}
.dropdown ul:hover,
.dropdown li:hover > ul,
.dropdown a:hover + ul,
.dropdown a:focus + ul {
    visibility:visible;
    display:block;
}
.dropdown a {
    display:block;
    padding:1em 2em;
}
.dropdown ul li {
    width:100%;
}

存在未知数量的顶级链接(它们由用户创建)。我遇到的问题是,有时,如果顶级链接到右边太远,下拉菜单(右侧)将离开屏幕。我添加了这个位的CSS来补偿:

.dropdown > li:last-child ul { /* ...or use a class on the last link for IE */
    right:0;
}

现在最后一个到左边,而不是关闭屏幕,这是很好,但有一些问题:

>我不总是需要这些样式的最后一个链接,因为它不总是在屏幕的边缘(如果只有3个链接)。
>当浏览器窗口调整大小时,链接堆叠在彼此之上(按设计)。有时,在序列中间的链接在右边缘结束,并且它们的下拉菜单被切断。
>有时“最后一个”链接的菜单也会超出边界。

调整此演示中的面板大小以查看我的意思(红色区域被认为是“屏幕外”)http://jsfiddle.net/G7qfq/

我已经努力与这个恼人的常见问题多年,从未找到一个令人满意的解决方案。有什么办法来检查下拉菜单是否会关闭屏幕,如果是,添加/删除类名或某事,所以我可以保持它在屏幕上的CSS?

我可能使用的一个线索是,如果一个菜单脱离屏幕,它总是产生一个垂直滚动条在窗口的底部,但我不知道如何使用这些知识。我试着接受this question关于检测垂直滚动条的答案,但由于某种原因它总是返回true,并总是添加“边缘”类(也许有一个时间问题?):

$(".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');
    }
});​

演示与javascript:http://jsfiddle.net/G7qfq/2/

真的,我不想看到一个垂直滚动条,即使是一秒钟,所以我不知道这是走的路,加上可能有误报(滚动条为一些其他原因)。

我也试过在this answer的解决方案,我承认,我不太明白,不能得到它的工作:http://jsfiddle.net/G7qfq/3/

$(".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');
    }
});​

我假设解决方案需要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');
            }
        }
    });
});

http://jsfiddle.net/G7qfq/582/

转载注明原文:javascript – 检测下拉菜单是否会关闭屏幕并重新定位 - 代码日志