【问题标题】:Why does DOM appendChild() fire on('load', ...) but jQuery append() does not?为什么 DOM appendChild() 会触发 ('load', ...) 而 jQuery append() 不会?
【发布时间】:2014-12-22 04:09:48
【问题描述】:

我有以下sn-ps的代码:

$(document).ready(function() {
    document.head.appendChild(
        $('<script />').attr('src', 'source.js').on('load', function() {
            ...
        })[0]
    );
});

这将触发负载处理程序。

而使用普通的 jQuery append():

$(document).ready(function() {
   $('head').append(
        $('<script />').attr('src', 'source.js').on('load', function() {
            ...
        })
    );
});

这不会触发负载处理程序。

我错过了什么:为什么 jQuery append() 不起作用?

使用document.head.appendChild() 是个坏主意吗?

注意:我不能使用$.getScript()。代码将在本地文件系统上运行,chrome 会抛出跨站脚本错误。


更新

有些人在阅读简洁风格时遇到了困难,所以我使用了额外的换行符来明确哪些对象调用了哪些方法。我还明确表示我的代码在 $(document).ready 块内。


解决方案

最后我选择了:

$(document).ready(function() {
    $('head')[0].appendChild(
        $('<script />').attr('src', 'source.js').on('load', function() {
            …
        })[0]
    );
});

我认为 @istos 是对的,因为 domManip 中的某些内容正在破坏 load

【问题讨论】:

  • 不知道为什么 jQuery 不起作用。使用本机 API 肯定不是一个坏主意,但如果您支持旧浏览器,有些不支持 document.head 属性。您要么需要从 DOM 中选择 head 元素,要么将其附加到 document.body
  • ...另外,我认为旧的 IE 不支持 onloadscript 元素。不知道 jQuery 是否能解决这个问题。
  • @squint 客户端不包括 IE(谢天谢地)。
  • 哇,你真幸运! :) 在这种情况下,我会完全放弃 jQuery。

标签: javascript jquery dom onload


【解决方案1】:

你不必完全抛弃 jquery,你可以使用 zeptojs。其次,我不知道这种行为究竟是如何发生的以及为什么会发生。尽管我觉得可以在下面的链接中找到答案。到目前为止,我可以告诉你,如果你在定义 src 元素之前插入元素,那么加载将不会触发。

但对于手动插入,这并不重要。 (??????)

但是,我发现如果您使用appendTo,它可以工作。 代码:http://jsfiddle.net/techsin/tngxnkk7/

var $ele = $('<script />').attr('src', link).load(function(){ abc(); }) ).appendTo('head');

新信息: 据了解,将 script 标签添加到带有 src 属性的 dom 中,启动 src 中提到的脚本的下载过程。手动插入会导致页面加载外部脚本,使用appendappendTo会导致jquery开始下载外部js文件。但是使用 jquery 附加事件并且 jquery 启动下载然后事件不会触发。但是,如果是页面本身启动了下载,那么它会启动下载。即使手动添加事件,没有jquery,通过jquery添加到dom也不会触发。

我认为应该是答案的链接...

Append Vs AppendChild JQuery

http://www.blog.highub.com/javascript/decoding-jquery-dommanip-dom-manipulation/

http://www.blog.highub.com/javascript/decoding-jquery-dommanip-dom-manipulation/

https://github.com/jquery/jquery/blob/master/src/manipulation.js#L477-523

http://ejohn.org/blog/dom-documentfragments/

【讨论】:

  • 我不确定这是在做什么?从我的代码中的$('&lt;script /&gt;').on('load',… 切换到您的代码中的$(this).load(…。在上下文中,this 对象应该是窗口。这是因为在所有脚本完成加载之前窗口不会触发加载吗?
【解决方案2】:

您可能应该确保在文档准备好时触发 jquery 追加。可能是附加触发时 head 实际上不在 dom 中。

【讨论】:

  • 我的代码已经在$(document).ready(… 中,我的问题中没有包含该详细信息。
【解决方案3】:

jQuery 在其 DOM 操作代码中做了一些有趣的事情。如果您查看 jQuery 的源代码,您会发现它在 append() 方法中使用了一个名为 domManip() 的方法。

这个domManip() 方法创建了一个文档片段(看起来该节点首先附加到一个“安全”片段)并且有很多关于脚本的检查和条件。我不确定它为什么使用文档片段或为什么存在所有关于脚本的检查但使用本机 appendChild() 而不是 jQuery 的 append() 方法会成功触发事件。代码如下:

直播 JSBin:http://jsbin.com/qubuyariba/1/edit

  var url = 'http://d3js.org/d3.v3.min.js';  
  var s = document.createElement('script');
  s.src = url;
  s.async = true;

  $(s).on('load', function(e) {
    console.log(!!window.d3); // d3 exists
    $(document.body).append('<h1>Load fired!</h1>');
  });

  $('head').get(0).appendChild(s);


更新:

appendChild() 是一种得到很好支持的方法,在这种情况下绝对没有理由不使用它。

【讨论】:

    【解决方案4】:

    也许问题是当你选择DOM appendChild时,实际上你调用的函数是document.on('load',function(){});,但是当你选择jQuery append()时,你的代码是$('head').on('load', function(){})

    documenthead 是不同的。

    您可以输入以下代码: $(document).find('head').append($('<script />').attr('src', 'source.js').end().on('load', function() { ... }));

    【讨论】:

    • 再看代码。 $('&lt;script /&gt;').attr('src', 'source.js').on('load', function() {}) 被传递给 $('head').append()
    猜你喜欢
    • 2011-01-27
    • 1970-01-01
    • 2014-06-11
    • 1970-01-01
    • 2011-04-17
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多