Vanilla JavaScript 等效于 jQuery 的 $ .ready() - 如何在页面/DOM 准备好时调用函数

29 浏览
0 Comments

Vanilla JavaScript 等效于 jQuery 的 $ .ready() - 如何在页面/DOM 准备好时调用函数

这个问题已经有答案了

没有jQuery的$(document).ready等效方法

使用jQuery,我们都知道美妙的.ready()函数:

$('document').ready(function(){});

然而,假设我想运行一个用标准JavaScript编写的没有库支持的函数,并且我想在页面准备好处理它时启动一个函数。正确的方法是什么?

我知道我可以这样做:

window.onload="myFunction()";

或者我可以使用body标签:


或者我甚至可以尝试在页面底部,在所有内容之后,但在bodyhtml标签之前:


有没有一种跨浏览器(旧/新)兼容的方法,以类似于jQuery的$.ready()的方式发出一个或多个函数?

admin 更改状态以发布 2023年5月21日
0
0 Comments

如果你在使用纯JavaScript而不是jQuery,那么你必须使用(Internet Explorer 9或更高版本):

document.addEventListener("DOMContentLoaded", function(event) {
    // Your code to run since DOM is loaded and ready
});

上面的代码相当于jQuery的.ready

$(document).ready(function() {
    console.log("Ready!");
});

也可以像这样用简写来编写,当jQuery准备好后会运行它:(发生)

$(function() {
    console.log("ready!");
});

不要与下面混淆(下面的代码不是DOM准备就绪):

不要像这样使用IIFE,使其自运行:

 Example:
(function() {
   // Your page initialization code here  - WRONG
   // The DOM will be available here   - WRONG
})();

这个IIFE不会等待DOM加载。 (我甚至谈论的是最新版本的Chrome浏览器!)

0
0 Comments

在没有一个框架可以为您完成所有跨浏览器兼容性的情况下,最简单的方法就是在 body 的末尾调用您的代码。这比 onload 处理程序更快,因为它仅等待 DOM 准备就绪,而不是等待所有图像加载完成。而且,这适用于所有浏览器。






Your HTML here




对于现代浏览器(从 IE9 及以上版本以及任何版本的 Chrome、Firefox 或 Safari),如果您想能够实现类似于 jQuery 的 $(document).ready() 方法,而不必担心调用脚本的位置,您可以使用类似于这样的东西:

function docReady(fn) {
    // see if DOM is already available
    if (document.readyState === "complete" || document.readyState === "interactive") {
        // call on next available tick
        setTimeout(fn, 1);
    } else {
        document.addEventListener("DOMContentLoaded", fn);
    }
}    


用法:

docReady(function() {
    // DOM is loaded and ready for manipulation here
});


如果您需要完全的跨浏览器兼容性(包括旧版本的 IE)并且您不想等待 window.onload,那么您可能应该去看一下像 jQuery 这样的框架如何实现它的 $(document).ready() 方法。这取决于浏览器的功能而有所不同。
为了让您对 jQuery 的操作有一个小的概念(在脚本标记放置的位置可以工作的代码)。
如果支持,它会尝试标准的:

document.addEventListener('DOMContentLoaded', fn, false);


并回退到:

window.addEventListener('load', fn, false )


或对于旧版本的 IE,则使用:

document.attachEvent("onreadystatechange", fn);


并回退到:

window.attachEvent("onload", fn);


而且,在 IE 代码路径中有一些解决方案,我不是很清楚,但它看起来与框架有关。


这里是一个完整的用纯 JavaScript 编写的 jQuery 的 .ready() 替代品:

(function(funcName, baseObj) {
    // The public function name defaults to window.docReady
    // but you can pass in your own object and own function name and those will be used
    // if you want to put them in a different namespace
    funcName = funcName || "docReady";
    baseObj = baseObj || window;
    var readyList = [];
    var readyFired = false;
    var readyEventHandlersInstalled = false;
    // call this when the document is ready
    // this function protects itself against being called more than once
    function ready() {
        if (!readyFired) {
            // this must be set to true before we start calling callbacks
            readyFired = true;
            for (var i = 0; i < readyList.length; i++) {
                // if a callback here happens to add new ready handlers,
                // the docReady() function will see that it already fired
                // and will schedule the callback to run right after
                // this event loop finishes so all handlers will still execute
                // in order and no new ones will be added to the readyList
                // while we are processing the list
                readyList[i].fn.call(window, readyList[i].ctx);
            }
            // allow any closures held by these functions to free
            readyList = [];
        }
    }
    function readyStateChange() {
        if ( document.readyState === "complete" ) {
            ready();
        }
    }
    // This is the one public interface
    // docReady(fn, context);
    // the context argument is optional - if present, it will be passed
    // as an argument to the callback
    baseObj[funcName] = function(callback, context) {
        if (typeof callback !== "function") {
            throw new TypeError("callback for docReady(fn) must be a function");
        }
        // if ready has already fired, then just schedule the callback
        // to fire asynchronously, but right away
        if (readyFired) {
            setTimeout(function() {callback(context);}, 1);
            return;
        } else {
            // add the function and context to the list
            readyList.push({fn: callback, ctx: context});
        }
        // if document already ready to go, schedule the ready function to run
        if (document.readyState === "complete") {
            setTimeout(ready, 1);
        } else if (!readyEventHandlersInstalled) {
            // otherwise if we don't have event handlers installed, install them
            if (document.addEventListener) {
                // first choice is DOMContentLoaded event
                document.addEventListener("DOMContentLoaded", ready, false);
                // backup is window load event
                window.addEventListener("load", ready, false);
            } else {
                // must be IE
                document.attachEvent("onreadystatechange", readyStateChange);
                window.attachEvent("onload", ready);
            }
            readyEventHandlersInstalled = true;
        }
    }
})("docReady", window);


该代码的最新版本在 GitHub 上公开共享,网址为:https://github.com/jfriend00/docReady
用法:

// pass a function reference
docReady(fn);
// use an anonymous function
docReady(function() {
    // code here
});
// pass a function reference and a context
// the context will be passed to the function as the first argument
docReady(fn, context);
// use an anonymous function with a context
docReady(function(context) {
    // code here that can use the context argument that was passed to docReady
}, ctx);


这已经经过以下测试:

IE6 and up
Firefox 3.6 and up
Chrome 14 and up
Safari 5.1 and up
Opera 11.6 and up
Multiple iOS devices
Multiple Android devices


工作实现和测试平台:http://jsfiddle.net/jfriend00/YfD3C/


以下是它的工作原理摘要:

  1. 创建一个立即调用的函数表达式(IIFE),以便我们可以拥有非公共状态变量。
  2. 声明一个公共函数docReady(fn, context)
  3. 当调用 docReady(fn, context) 时,检查是否已经触发了 ready 处理程序。如果是,则只需在此 JS 线程完成后使用 setTimeout(fn, 1) 计划新添加的回调即可。
  4. 如果 ready 处理程序尚未触发,则将此新回调添加到要稍后调用的回调列表中。
  5. 检查文档是否已准备就绪。如果是,则执行所有 ready 处理程序。
  6. 如果我们尚未安装事件侦听器以了解文档何时准备就绪,则现在安装它们。
  7. 如果 document.addEventListener 存在,则使用 .addEventListener()"DOMContentLoaded""load" 事件安装事件处理程序。"load" 是一种备用事件,用于安全起见,不应该需要。
  8. 如果 document.addEventListener 不存在,则使用 .attachEvent()"onreadystatechange" " onload " 事件安装事件处理程序。
  9. onreadystatechange 事件中,检查 document.readyState === "complete" 是否为真。如果是,请调用一个函数来触发所有 ready 处理程序。
  10. 在所有其他事件处理程序中,调用一个函数以触发所有 ready 处理程序。
  11. 在调用所有准备处理程序的函数中,检查一个状态变量,以查看我们是否已经启动。如果我们已经启动,则无事可做。如果我们尚未调用,则循环遍历准备好的函数数组,并按它们添加的顺序依次调用每个函数。设置一个标志以指示已经调用了所有的处理程序,以便它们永远不会被执行多次。
  12. 清除函数数组,以便可以释放它们可能正在使用的任何闭包。

使用docReady() 注册的处理程序保证按注册顺序触发。

如果您在文档已准备好之后调用 docReady(fn),则回调将被安排在当前执行线程完成后立即执行,使用 setTimeout(fn, 1)。 这使得调用代码始终可以假设它们是异步回调,即使稍后是指当前 JS 线程完成后,也会保留调用顺序。

0