检测下拉导航是否会离开屏幕并重新定位

时间:2012-07-16 20:30:03

标签: 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 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;
}

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

  1. 我并不总是需要这些样式用于最后一个链接,因为它并不总是在屏幕的边缘(如果只有3个链接)。
  2. 当浏览器窗口调整大小时,链接堆叠在一起(按设计)。有时,序列中间的链接最终会出现在右边缘,并且它们的下拉列表会被切断。
  3. 有时候,“倒数第二个”链接的菜单也会超出边界。
  4. 调整此演示中的面板大小以查看我的意思(红色区域被视为“屏幕外”) http://jsfiddle.net/G7qfq/

    多年来,我一直在努力解决这个令人烦恼的常见问题,但从未找到过令人满意的解决方案。有没有办法检查下拉菜单是否会关闭屏幕,如果是这样,添加/删除class名称或其他什么,以便我可以使用CSS将其保留在屏幕上?

    我可能会使用的一个线索是,如果菜单 离开屏幕,它总是在窗口底部生成一个垂直滚动条,但我不知道如何使用该知识。我尝试了this question关于检测垂直滚动条的已接受答案,但由于某种原因,它总是返回true,并且总是添加“边缘”类(可能是时间问题?):< / p>

    $(".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,但我还没有弄清楚如何解决问题。有什么想法吗?

3 个答案:

答案 0 :(得分:52)

我觉得你差不多......

您应该只对宽度涉及的计算感兴趣。如果下拉元素的宽度和该元素的偏移量大于容器的宽度,则需要切换菜单。

$(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/

答案 1 :(得分:3)

这是一个可以用于向右或向下飞出的菜单的功能(基于@ r0m4n的代码):

`cordova platform add ios`

答案 2 :(得分:0)

我无法使addClass('edge')正常工作,但是我可以修改相关元素的CSS来实现此行为。 (仅从r0m4n稍作修改):

spl <- unname(lapply(df[-1], strsplit, ","))
lengths(do.call(Map, c(intersect, spl)))
#[1] 1 2 1