jQuery偏移顶部取值错误,但在页面调整大小时获取正确值

5
我希望实现一个类似于此页面左侧导航的固定菜单:http://getbootstrap.com/2.3.2/scaffolding.html。我的菜单是一个具有position:relative(我也尝试过static)属性的nav元素,当它到达视口的顶部时,变为fixed状态。以下是我的功能代码:
$(document).ready(function() {
    function stickyNav() {
        var elementPosition = $('nav').offset();
        console.log(elementPosition);

        $(window).scroll(function(){
            if($(window).scrollTop() > elementPosition.top){
                $('nav').addClass("sticky");
            } else {
                $('nav').removeClass("sticky");
            }
        });
    }
    stickyNav();
}); //document ready
console.log(elementPosition); 返回的偏移顶部值是错误的,大约为1200px,但如果我调整页面大小,值会更改为大约650px,这才是正确的偏移顶部值,函数才能按照其预期执行。
我查看了一些资料发现,当偏移顶部值在隐藏元素上时,或者它存在边距问题时,偏移顶部值可能会出错,但事实上,在这里我没有任何复杂的结构,只有一个单一可见的 nav 元素。
如有帮助解决此问题的相关信息,将不胜感激!谢谢!!

你的代码中在哪里调用了stickyNav()函数?我没有看到它被调用。能否分享一下导致这个问题的nav标签的HTML代码? - Dennis Shtatnov
@DennisShtatnov 已更新,感谢。 - valerio0999
这是您的代码最小功能示例的工作方式:https://jsfiddle.net/b4m3swhp/1/。我怀疑它与< nav>放置的结构或插入时间有关。如果调整大小可以解决问题,则可能是您的css具有响应性并在屏幕特定宽度时影响< nav>标记。 - Dennis Shtatnov
2个回答

3

jQuery(document).ready事件会在DOM准备就绪时触发,而不是在页面完全渲染后触发。

https://api.jquery.com/ready/

当使用依赖于CSS样式属性值的脚本时,重要的是在引用脚本之前引用外部样式表或嵌入样式元素。

在代码依赖于已加载资源的情况下(例如,如果需要图像的尺寸),应将代码放置在load事件处理程序中。

因此,如果您正在使用在问题脚本之后加载的样式表,或者页面布局依赖于图片大小或其他内容,则ready事件会在页面没有处于其最终渲染状态时被触发。

您可以通过以下方式解决此问题:

  1. 确保在脚本之前包含所有样式表
  2. 确保CSS更加健壮,并且不过度依赖内容大小(如图像)
  3. 或者,您可以在window load事件上执行此操作。

编辑:

如果您想使脚本依赖于多个异步事件(如loadCSS库),请使用以下代码:

var docReady = jQuery.Deferred();
var stylesheet = loadCSS( "path/to/mystylesheet.css" );
var cssReady = jQuery.Deferred();
onloadCSS( stylesheet, function() {
    cssReady.resolve();
});
jQuery(document).ready(function($) {
    docReady.resolve($);
});
jQuery.when(docReady, cssReady).then(function($) {
    //define stickyNav

    stickyNav();
});

这是一个很好的答案!事实上,我的CSS是异步加载的(https://github.com/filamentgroup/loadCSS),这可能是为什么会发生这种情况吗?有没有办法在CSS被附加后让函数启动?谢谢。 - valerio0999
你可以为每个异步加载创建一个 Deferred jQuery 对象:文档准备就绪、CSS 加载等。在每次加载后,只需解决承诺即可。 因此,将您的代码放在 jQuery.when(promises).then(functionWhenAllIsOk, functionWhenNotAllOk) 中。https://api.jquery.com/jQuery.when/您可以使用以下方法与您的 loadCSS 一起使用: var stylesheet = loadCSS( "path/to/mystylesheet.css" ); onloadCSS( stylesheet, function() { console.log( "Stylesheet has loaded." ); }); - Alex

-1
您可以通过在文档中设置一个样式标签来显示测试元素,然后在CSS文件中覆盖它以隐藏它,从而添加一个检查以查看CSS是否已加载。然后,您可以通过检查此元素来检查页面的状态。例如...

在您的HTML中:

<div id="loaded-check" style="display:block; height:10px; width:10px; position:fixed;"></div>

在你的 CSS 中:
#loaded-check { display:none; }

在你的jQuery脚本中:
var startUp = function() {
    var cssLoaded = $('#loaded-check').is(':visible');
    if (cssLoaded) {
        $('#loaded-check').remove();
        doOtherStuff()
    }
    else {
        setTimeout(function() {
            startUp();
        }, 10);
    }
}

var doOtherStuff = function () {
    //bind your sticky menu and any other functions reliant on DOM load here
}

这正是 onload 事件的用途。 - JonMack
实际上,onload事件是在DOM加载完成后触发的,与浏览器应用CSS样式无关。这两个事件之间通常存在延迟。我经常看到人们使用超时来尝试避免在页面加载过早时获取元素高度或偏移量。我的解决方案只是比那更加控制一些。 - DoubleA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接