【问题标题】:javascript:how to write $(document).ready like event without jqueryjavascript:如何在没有 jquery 的情况下编写 $(document).ready 之类的事件
【发布时间】:2011-04-28 16:39:52
【问题描述】:

在 jquery $(document).ready(function) 或 $(function) 中,没有 jquery 我怎么能做同样的事情,我需要浏览器兼容,并允许附加多个函数。

注意:dom 就绪!= 窗口加载

【问题讨论】:

  • 我查看了 jQuery 源代码,其中有相当多的代码与 ready() 处理程序相关。如果我正确阅读了代码,则该事件称为DOMContentLoaded。 IE不支持,所以改用onreadystatechange
  • 另外,它与 document.readyState 的值 "complete" 有关
  • @Šime Vidas:它与很多事情有关(iframe 加载有其自身的怪癖?谁知道呢?),坦率地说,这是一段了不起的代码。我被提醒了为什么我不再直接注册事件 - 这是一个主要的 PITA正确
  • 我相信你最好使用 jQuery 而不是重新发明轮子。它有太多的怪癖(阅读浏览器兼容性问题)要考虑

标签: javascript domready


【解决方案1】:

这是 jQuery 包装您正在寻找的函数的方式 - sn-p 不需要 jQuery,并且是跨浏览器兼容的。我已将所有对 jQuery.ready() 的调用替换为 yourcallback - 您需要定义它。

这里发生了什么:

  • 首先,定义函数DOMContentLoaded,当DOMContentLoaded 事件触发时将使用该函数——它确保回调只被调用一次。
  • 检查文档是否已加载 - 如果是,立即触发回调
  • 否则嗅探特征 (document.addEventListener / document.attachEvent) 并将回调绑定到它(IE 和普通浏览器不同,加上 onload 回调)

Lifted from jQuery 1.4.3, functions bindReady() and DOMContentLoaded:

/*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
// Cleanup functions for the document ready method
// attached in the bindReady handler
if ( document.addEventListener ) {
DOMContentLoaded = function() {
    document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
    //jQuery.ready();
            yourcallback();
};

} else if ( document.attachEvent ) {
DOMContentLoaded = function() {
    // Make sure body exists, at least, in case IE gets a little overzealous 
            if ( document.readyState === "complete" ) {
        document.detachEvent( "onreadystatechange", DOMContentLoaded );
        //jQuery.ready();
                    yourcallback();
    }
    };
}

// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
    // Handle it asynchronously to allow scripts the opportunity to delay ready
//return setTimeout( jQuery.ready, 1 );
    // ^^ you may want to call *your* function here, similarly for the other calls to jQuery.ready
    setTimeout( yourcallback, 1 );
}

// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
    // Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
//window.addEventListener( "load", jQuery.ready, false );
    window.addEventListener( "load", yourcallback, false );
 // If IE event model is used
 } else if ( document.attachEvent ) {
        // ensure firing before onload,
        // maybe late but safe also for iframes
        document.attachEvent("onreadystatechange", DOMContentLoaded);

        // A fallback to window.onload, that will always work
        window.attachEvent( "onload", yourcallback );

 }

这是 51 行纯 JavaScript 代码,只是为了可靠地注册事件。据我所知,没有更简单的方法。去展示像 jQuery 这样的包装器有什么好处:它们包装了能力嗅探和丑陋的兼容性问题,以便您可以专注于其他事情。

【讨论】:

  • 我得说要知道何时初始化使用 DOM 的脚本有很多复杂的代码......就像我在回答中发布的那样,我只是在 close 正文之后调用一个初始化函数标签
  • @Juan Mendes:是的,它做的事情表面上很相似——但内联脚本标签也有其怪癖:例如,在 咳咳 某些浏览器中阻止并行下载。并且不要忘记整个“让我们在 DOM 仍在加载时修改它”的乐趣。这就是为什么我宁愿使用 $.ready() - 一个在 Google 的 CDN 上缓存良好的库,然后是一个运行良好的函数调用,It Just Works。但如果你想重新发明自 1997 年以来的所有 JS hack,那就继续吧。
  • @Piskvor:“但是,如果你想重新发明自 1997 年以来的所有 JS 黑客,那就继续吧”?这是怎么回事?我认为这是一个简单(优雅)的解决方案。如果您在 body 标记之后放置一个 script 标记,则可以保证 DOM 已准备就绪,而不是“让我们在 DOM 仍在加载时对其进行修改”
  • @Juan Mendes:抱歉,我有点走神了。
  • 你能在页面底部指出一些关于怪癖模式和脚本的内容吗? developer.yahoo.com/performance/rules.html 是建议您始终将脚本留在页面底部的链接。
【解决方案2】:

Smallest DOMReady code, ever.

<html>
  <head>
    <script>
      var ready = function (f) {
        (/complete|loaded|interactive/.test(document.readyState)) ?
            f() :
            setTimeout(ready, 9, f);
      };
    </script>
  </head>
  <body>
    <script>
      ready(function () {
        alert('DOM Ready!');
      });
    </script>
  </body>
</html>

【讨论】:

  • 快速提问:什么是“r”函数?在 FF 中尝试此操作时出现错误。
  • 请注意,这在后台使用eval()。但是很酷的骗子!
  • 如果您不在 ie 中,请使用“setTimeout(ready, 9, f)”,如果您在,请使用“setTimeout(function () { ready(f); }, 9)”
  • 你的情况正好相反。
【解决方案3】:

如果您支持 IE9+ 和现代 (2013) 版本的 Chrome、FF、Safari 等,这就是您所需要的一切。

function ready(event) {
    // your code here
    console.log('The DOM is ready.', event);
    // clean up event binding
    window.removeEventListener('DOMContentLoaded', ready);
}

// bind to the load event
window.addEventListener('DOMContentLoaded', ready);

【讨论】:

    【解决方案4】:

    这是我使用的一种似乎可靠的方法

    function ready(func) {
      var span = document.createElement('span');
      var ms = 0;
      setTimeout(function() {
        try {
          document.body.appendChild(span);
    
          document.body.removeChild(span);
    
          //Still here? Then document is ready
          func();
        } catch(e) {
          //Whoops, document is not ready yet, try again...
    
          setTimeout(arguments.callee, ms);
        }
      }, ms);
    }
    

    很简单,它只是不断尝试将一个空的&lt;span&gt; 元素附加到document.body。如果文档未“准备好”,则会引发异常,在这种情况下,它会再次尝试使用新的 setTimeout 调用。一旦没有抛出异常,就会调用回调函数。

    如果这种方法有任何问题,我很乐意听到。它对我来说效果很好,但我还没有进行任何流行的 Javascript 框架都应该进行的广泛测试。

    【讨论】:

    • 两个字:内存泄漏。在较旧的浏览器上,随着所有元素的添加和删除,您将疯狂地泄漏内存。另外,您正在 JavaScript 中重新实现忙等待循环(这不是最有效的语言)。
    • 我没看到。使用这种方法,当文档准备好时,元素只会被添加和删除一次。即使这样,在超时函数之外的内存中也只会创建一个元素。此外,延迟为 0 毫秒的 setTimeout/setInterval 与条件 while 循环不同。由于 JS 中计时器的工作方式,以及本示例中超时函数中操作的简单性,性能应该不会受到显着影响。
    【解决方案5】:

    我见过很多不同的方法来尝试做到这一点。最简单的方法(我认为最初是雅虎建议的)是在 close body 标记之后调用你的初始化函数,有点突兀,但它是一行。

    【讨论】:

      【解决方案6】:

      编辑

      DomReady 事件在 JavaScript 中不存在。您可以按照 Dean Edwards herehere 等人所做的一些出色工作来实现自己的工作,您可以在文档而不是窗口上执行类似的事件附件过程。


      查看 user83421 对How do I add an additional window.onload event in Javascript的回复

      这里也回顾一下。

      if (window.addEventListener) // W3C standard
      {
        window.addEventListener('load', myFunction, false); // NB **not** 'onload'
      } 
      else if (window.attachEvent) // Microsoft
      {
        window.attachEvent('onload', myFunction);
      }
      

      【讨论】:

      • 您拥有的 sn-p 仅用于加载事件
      【解决方案7】:

      我在“close body”标签之后和“close html”标签之前有这个。它工作得很好。加载预设功能将宽度、高度和位置值分配给 css div 标签。适用于不同的屏幕尺寸。

      document.onreadystatechange = function () {
      if  (document.readyState == "interactive") {
      loadPresets();
      }
      

      }

      【讨论】:

        猜你喜欢
        • 2012-04-04
        • 1970-01-01
        • 2011-04-27
        • 1970-01-01
        • 2010-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多