我有一个使用$(document).ready的脚本,但它不使用jQuery中的任何其他内容。我想通过删除jQuery依赖项来减轻它。

如何在不使用jQuery的情况下实现我自己的$(document).ready功能?我知道,使用window.onload将不同,因为window.onlead在加载所有图像、帧等后启动。


当前回答

大多数普通的JS Ready函数都不考虑在文档加载后设置DOMContentLoaded处理程序的情况——这意味着函数永远不会运行。如果在异步外部脚本(<script async src=“file.js”></script>)中查找DOMContentLoaded,则可能会发生这种情况。

只有当文档的readyState尚未交互或完成时,下面的代码才会检查DOMContentLoaded。

var DOMReady = function(callback) {
  document.readyState === "interactive" || document.readyState === "complete" ? callback() : document.addEventListener("DOMContentLoaded", callback());
};
DOMReady(function() {
  //DOM ready!
});

如果您也想支持IE:

var DOMReady = function(callback) {
    if (document.readyState === "interactive" || document.readyState === "complete") {
        callback();
    } else if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', callback());
    } else if (document.attachEvent) {
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState != 'loading') {
                callback();
            }
        });
    }
};

DOMReady(function() {
  // DOM ready!
});

其他回答

一旦DOM就绪,此跨浏览器代码将调用函数:

var domReady=function(func){
    var scriptText='('+func+')();';
    var scriptElement=document.createElement('script');
    scriptElement.innerText=scriptText;
    document.body.appendChild(scriptElement);
};

以下是它的工作原理:

domReady的第一行调用函数的toString方法,以获取传入函数的字符串表示形式,并将其包装在立即调用该函数的表达式中。domReady的其余部分使用表达式创建一个脚本元素,并将其附加到文档正文中。DOM就绪后,浏览器运行附加到主体的脚本标记。

例如,如果您这样做:domReady(function(){alert();});,以下内容将附加到body元素:

 <script>(function (){alert();})();</script>

注意,这只适用于用户定义的函数。以下命令不起作用:domReady(警报);

我最近在一个移动网站上使用这个。这是John Resig的简化版“Pro JavaScript技术”。它取决于addEvent。

var ready = ( function () {
  function ready( f ) {
    if( ready.done ) return f();

    if( ready.timer ) {
      ready.ready.push(f);
    } else {
      addEvent( window, "load", isDOMReady );
      ready.ready = [ f ];
      ready.timer = setInterval(isDOMReady, 13);
    }
  };

  function isDOMReady() {
    if( ready.done ) return false;

    if( document && document.getElementsByTagName && document.getElementById && document.body ) {
      clearInterval( ready.timer );
      ready.timer = null;
      for( var i = 0; i < ready.ready.length; i++ ) {
        ready.ready[i]();
      }
      ready.ready = null;
      ready.done = true;
    }
  }

  return ready;
})();

比较

这里(在下面的片段中)是所选择的可用浏览器“内置”方法及其执行顺序的比较。评论

任何现代浏览器都不支持document.onload(X)(从不触发事件)如果您使用<body onload=“bodyOnLoad()”>(F),同时使用window.onload(E),则只执行第一个(因为它会覆盖第二个)<body onload=“…”>(F)中给定的事件处理程序由附加的onload函数包装document.onreadystatechange(D)不覆盖document.addEventListener('readystatechange'…)(C)可能是因为类似XYZevent的方法独立于addEventListener队列(允许添加多个侦听器)。在执行这两个处理程序之间可能不会发生任何事情。所有脚本都在控制台中写入时间戳,但也可以访问div的脚本也在主体中写入时间标记(在脚本执行后单击“FullPage”链接查看)。解决方案readystatechange(C,D)由浏览器执行多次,但针对不同的文档状态:loading-文档正在加载(没有在代码段中激发)交互式-文档在DOMContentLoaded之前被解析和激发完成-加载文档和资源,在加载body/window之前激发

<html><head><脚本>//溶液Aconsole.log(`[timestamp:${Date.now()}]A:Head脚本`);//溶液Bdocument.addEventListener(“DOMContentLoaded”,()=>{print(`[时间戳:${Date.now()}]B:DOMContentLoaded`);});//溶液Cdocument.addEventListener('readystatechange',()=>{print(`[时间戳:${Date.now()}]C:就绪状态:${document.ReadyState}`);});//溶液Ddocument.onreadystatechange=s=>{print(`[时间戳:${Date.now()}]D:document.onrreadystatechange就绪状态:${document.ReadyState}`)};//解决方案E(从未执行)window.onload=()=>{print(`E:<body onload=“…”>覆盖此处理程序`);};//溶液F函数体OnLoad(){print(`[timestamp:${Date.now()}]F:<body onload='…'>`);infoAboutOnLoad();//其他信息}//溶液Xdocument.onload=()=>{print(“document.onlead从未启动”)};//助手函数打印(txt){console.log(txt);如果(mydiv)mydiv.innerHTML+=txt.replace('<','&lt;').replace('>','&gt;')+'<br>';}函数infoAboutOnLoad(){console.log(“window.onload(重写后):”,(“”+document.body.onload).replace(/\s+/g,“”));console.log(`body.onload==window.onload-->${document.body.onload==window.onload}`);}console.log(“window.onload(覆盖前):”,(“”+document.body.onload).replace(/\s+/g,“”));</script></head><body onload=“bodyOnLoad()”><div id=“mydiv”></div><!-- 此脚本必须位于<body>-->的底部<脚本>//溶液Gprint(`[timestamp:${Date.now()}]G:<body>底部脚本`);</script></body></html>

现在你应该使用模块。将代码放入模块的默认函数中,并将该函数导入脚本元素。

客户端.js:

export default function ()
{
  alert ("test");
}

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>test</title>
  </head>
  <body>
    <script type="module">
      import main from './client.js';
      main ();
    </script>
  </body>
</html>

以下是测试DOM就绪的最小代码片段,它适用于所有浏览器(甚至IE 8):

r(function(){
    alert('DOM Ready!');
});
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}

看到这个答案。