jQuery .length是否准备好DOM?

问题描述 投票:0回答:3

我有这个代码:

功能loader()将继续运行,直到<body>确实存在。当<body>确实存在时,插入.loader

<html>
<head>
<script type="text/javascript" src="jquery/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
    loader();
    function loader() {
        if (!$('body').length) {
            window.requestAnimationFrame(loader);
        } else {
            $('<div class="loader"></div>').prependTo('body');
        }
    };
</script>
</head>
<body>
    <!-- elements -->
</body>
</html>

我想问这一行

if (!$('body').length) {}

.length用什么来确定它的回报,是<body>还是<body></body>.length是否在等待关闭标签</body>?如果是的话,我的替代方案是什么?我需要插入.loader而不必等待</body>

我的最后一招是

<body>
    <div class="container"></div>
    <!-- rest of elements -->
</body>

那么

if (!$('.container').length) {}

但我需要不影响元素结构的替代品。

编辑:

我重新提出问题并添加以下代码。

<html>
<head>
<script type="text/javascript" src="jquery/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
    $(function(){
        console.log("ready timestamp");
    });
    loader();
    function loader() {
        if (!$('body').length) {
            window.requestAnimationFrame(loader);
        } else {
            console.log("length timestamp");
        }
    };
</script>
</head>
<body>
    <!-- elements -->
</body>
</html>

输出:

15:03:19.862 length timestamp
15:03:20.198 ready timestamp

长度时间戳始终低于就绪时间戳。

经测试:

Chrome 71.0和FF 65.0

在控制台设置中启用时间戳(开发人员工具 - >控制台 - >显示时间戳)。

其他人可能会问我为什么这样做,300ms左右是什么?

我实现PWA并需要加载器,如下所示:Showing loader while navigating between pages - PWA。问题是,上一页的.on('beforeunload')与下一页的$()之间有300毫秒。显然,这是个昙花一现。

这个blip可以理想地/容易地通过服务器端脚本解决,但正如我上面提到的,我无法访问服务器端脚本,我可以问的最远的是一个空白元素<div class="container"></div>

javascript jquery html
3个回答
1
投票

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
  console.log( $('#tryToFindMe').length );
</script>
<div id="tryToFindMe"></div>

与您的问题在定义之前尝试访问主体的方式类似,此代码段尝试在定义之前访问div。在这两种情况下,都不会找到该元素。

这是因为当您的浏览器将您的网页解析为文档对象模型时,它会从上到下进行解析。因此,在脚本运行时,将在DOM中创建div的html尚未处理。因此脚本尝试查找元素,它不存在,长度为零。

这就是为什么使用jQuery文档准备好,绑定到DOMContentLoaded事件或load事件的原因。这些不同的方法推迟了逻辑的执行,直到整个页面被解析为DOM,或者在加载的情况下,不仅页面已被解析到DOM中,而且所有资源都已被接收(图像,视频等)。如果没有这些方法,脚本将需要在定义元素后出现在页面中,以确保元素已存在于DOM中。

在考虑与DOM交互时,重要的一点是不要用HTML来思考。 DOM包含节点,而不是HTML。节点是从HTML生成的。


0
投票

您可以像这样使用jQuery文档就绪函数($(() => {})):

$(() => {
    $(`<div class="loader"></div>`).prependTo("body");
});

0
投票

我跑了另一个测试。

<html>
<head>
<script type="text/javascript" src="jquery/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
    $(function(){
        console.log("ready timestamp");
    });
    loader_bottom();
    loader_body();
    loader_top();
    function loader_bottom() {
        if (!$('.container_bottom').length) {
            window.requestAnimationFrame(loader_bottom);
        } else {
            console.log("container_bottom.length timestamp");
        }
    };
    function loader_top() {
        if (!$('.container_top').length) {
            window.requestAnimationFrame(loader_top);
        } else {
            console.log("container_top.length timestamp");
        }
    };
    function loader_body() {
        if (!$('body').length) {
            window.requestAnimationFrame(loader_body);
        } else {
            console.log("body.length timestamp");
        }
    };
</script>
</head>
<body>
    <div class="container_top"></div>
    <!-- elements between -->
    <div class="container_bottom"></div>
</body>
</html>

输出:

09:09:16.894 body.length timestamp
09:09:16.897 container_top.length timestamp
09:09:17.090 container_bottom.length timestamp
09:09:17.220 ready timestamp

因为$('.container_top')$('body')相邻,改变了序列,

loader_top();
loader_body();

毫不奇怪的输出:

09:09:39.708 container_top.length timestamp
09:09:39.708 body.length timestamp

因此我得出结论:

  1. jQuery .length是否准备好DOM?是的,它确实。
  2. .length用什么来确定它的回报,是<body>还是<body></body>?这是<body>

虽然第二个问题的正确短语应该是:DOM Parser用什么来确定节点,是<tag>还是<tag></tag>?答案是<tag>

实际上,我并不感到惊讶,我们可以在它准备好之前操纵DOM。此外,$().ready()只是DOM准备好的事件。 Javascript是多线程所以(我认为)DOM操作应该可以与DOM解析并行运行。直到这段代码我才能证明这一点。

© www.soinside.com 2019 - 2024. All rights reserved.