$(document).ready()触发太早了

36

所以,我需要使用JavaScript获取一个元素的宽度,但我的问题是函数在太早触发,当CSS完全应用时宽度会发生变化。据我所知,$(document).ready()函数在文档完成时被触发,但它似乎并不像这样工作。

无论如何,我相信通过代码可以理解我的问题(以下是一个简化的示例):

<html>
<head>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <link href='http://fonts.googleapis.com/css?family=Parisienne' rel='stylesheet' type='text/css'>

    <style type="text/css">
        #target {
            font-family: 'Parisienne', cursive;
            float: left;
        }
    </style>
</head>
<body>
    <div id="target">Element</div>
</body>
</html>

<script type="text/javascript">
    $(document).ready(function(){
        console.debug($('#target').outerWidth());
        alert('hold on');
        console.debug($('#target').outerWidth());
    });
</script>

我想知道 #target div 的宽度,问题在于在弹出警告框之前执行的代码和之后执行的代码给出不同的输出,可能是因为字体没有完全加载而且正在使用默认字体测量 div 的大小。

在 Google Chrome 中按照我的期望工作,但在 IE 和 Firefox 中不起作用。


我可以确认2013-11-24,当你点击浏览器的刷新按钮时,这个问题在JQuery 2.x上仍然存在。请访问此fiddle。当您首次加载fiddle时,大多数情况下一切都应该正常工作。如果您将鼠标光标放在URL中并按Enter键,则它也有效。但是,如果您单击刷新按钮或按CTRL+R,事情就会变得一团糟。 - Martin Andersson
我尝试实现了一个“倒计时门闩”,以便在窗口加载和相关字体完成加载时才测量宽度和高度。请查看以下链接:http://jsfiddle.net/jLDbX/1/。在这个示例中,一切似乎都正常工作。但是在我的真实应用程序中,我一直收到错误信息。不过对于您来说,也许可以正常工作。 - Martin Andersson
7个回答

73
如果你依赖于外部内容已经加载完成(例如图片、字体),你需要使用 window.load 事件。
$(window).on("load", function() {
    // code here
});

这些事件的行为在这篇文章中有所描述:

然而,还有一种名为DOM-ready的准备状态。这是当浏览器实际构建页面但仍可能需要获取一些图像或Flash文件时的状态。

编辑:根据 Alex H 的说明,更改了语法以使其与jQuery 3.0一起使用。


5
两年后,仍然有帮助! - Stachu
6
在JQuery 3.0中,你应该使用语法$(window).on('load', function() { });来取代已经被弃用的$(window).load()。 - Alex
@AlexH,说得好。$(window).load()在jQuery 1.8中已被弃用。此外,这很令人困惑,因为jQuery中有两个.load()方法(在事件处理程序之前的那个已被删除)。 - ryanpcmcquen
由于这是最佳答案,值得一提的是,在jQuery 3.0中,_on_方法已被弃用,应该使用.ready()/.load() https://api.jquery.com/ready/#ready-handler - darth0s
1
@darth0s 不,$(window).on('load',...) 语法没有改变,而 $(window).load() 实际上已被移除。不过你关于 .ready() 的说法是正确的。 - Mira Weller
$(document).ready() 在我的生产环境中可以正常工作,但在我的XAMPP本地服务器上却不行。 <耸肩>. $(window).on("load", function()) 解决了这个问题。谢谢。 - undefined

12

引用原帖:

"我理解的是,$(document).ready()函数在文档完成时被触发。"

$(document).ready()会在DOM("文档对象模型")完全加载并准备好操作时触发。DOM不同于"文档"。

W3C - DOM常见问题

你可以尝试使用$(window).load()函数代替...

$(window).load(function() {
    // your code
});

在触发之前,它将等待页面的所有资源(例如图像和字体等)完全加载。


5

jQuery的.ready()函数在DOM完成后立即触发。这并不意味着此时所有资源(例如图像、CSS等)都已加载,因此元素的大小可能会发生变化。

如果您需要元素的大小,请使用$(window).load()。


4

"ready"事件在DOM加载完成后触发,这意味着可以安全地使用标记。

如果要等待所有资产加载完成(css,图像,外部javascript...),最好使用load事件。

$(window).load(function() {
    ...
});

2

您可以使用$(window).load(),但这会等待所有资源(例如图像等)。如果您只想等待字体加载完成,可以尝试以下内容:

<script type="text/javascript"> 
    var isFontLoaded = false;
    var isDocumentReady = false;
    $("link[href*=fonts.googleapis.com]").load(function () {
        isFontLoaded = true;
        if (isDocumentReady) {
            init();
        }
    });
    $(document).ready(function () {
        isDocumentReady = true;
        if (isFontLoaded) {
            init();
        }
    });
    function init () {
        // do something with $('#target').outerWidth()
    }
</script> 

免责声明:我不确定这个方法是否有效。在样式表被解析但其外部资源尚未下载完成时,<link> onload事件可能会触发。也许您可以添加一个隐藏的<img src="fontFile.eot" />元素,并将onload处理程序放在该图像上。

1
有时候会出现问题$(document).ready() fires too early,这可能是因为您错误地声明了jQuery onReady函数。
如果遇到问题,请确保您的函数声明与以下代码完全相同:
 $(document).ready(function() 
 {
   // put your code here for what you want to do when the page loads.
 });

例如,如果您忘记了匿名函数部分,代码仍将运行,但它将会“无序”运行。
console.log('1');
$(document).ready()
{
  console.log('3');
}
console.log('2');

这将输出


1
3
2

1
我在IE9和IE10中多次遇到同样的问题。Jquery的ready()调用会触发,但我的某个
不存在。如果我检测到这一点,并在短暂的timeout()之后再次调用它,就可以正常工作。
我的解决方案是为了安全起见:
1. 在文档末尾添加,然后在ready()回调中检查该变量,以及 2. 检查$('#lastElementInTheDocument').length > 0
是的,我知道这些都是恶劣的hack。但是,当ready()不能按预期工作时,需要某种解决方法!
顺便说一下,“正确”的解决方案可能涉及在头部设置$.holdReady,并在文档末尾清除它。但当然,真正正确的解决方案是让ready()正常工作。

我也遇到了这个问题。也许解决方法是将document.ready命令放在页面底部,这似乎是现在更常见的做法。我也遇到了这个问题,但我目前将我的document.ready命令放在<head>标签中。 - hairbo

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