检测到正在加载到 DOM、jQuery 的新图像未触发加载事件处理程序

Detect new images being loaded into DOM, jQuery load event-handler does not fire

我正在开发一个用户脚本,它可以对图像执行各种操作。

问题是,有时图像会在初始加载后添加到页面,而我的用户脚本不会处理这些图像。

我需要 javascript/jQuery 中的一些代码,它会在每次将新图像加载到浏览器时自动 运行 一个函数。

这是我试过的:

$('img').on('load', function() {
    handleImgTag();
});

这不起作用。当新图片添加到页面时(我正在使用 chat.whosebug.com 作为测试,并发送一条新消息,这意味着我的个人资料图片再次添加到页面,但我的代码没有处理)图像不是已处理,但没有任何反应。

我试过四处搜索,但我似乎找不到解决方法,可能是因为搜索词不当?

是否有我可以在 Tampermonkey 用户脚本中使用的事件或其他东西,当新图像添加到用户所在的页面时,它会 运行 一个函数?

编辑:

我不同意提到的重复项,因为这是专门针对图像的,并且在 Tampermonkey 用户脚本中使用。此外,重复项已有 5-8 年历史,可能无法反映最佳实践或当前技术。

$('img').on('load',... 将无法工作,因为它将匿名事件处理程序发送到所有 现有 图像上。他们从不执着于未来,AJAX'd/Dynamically 插入的图像。

正确的形式 应该是:$('body').on ('load', 'img', handleImgTag);EXCEPT load events do not bubble.

因此,您必须使用:链接问题中的技巧(主要是 MutationObserver),或类似 waitForKeyElements().
的技巧 并且,您必须动态附加加载事件(对于加载缓慢的图像)。

以下完整的工作脚本说明了该过程。请注意,无论是静态加载还是动态加载,waitForKeyElements 都会为每个 <img> 触发一次。 :

// ==UserScript==
// @name     _Process select images on or after load
// @match    *://chat.whosebug.com/rooms/*
// @match    *://chat.stackexchange.com/rooms/*
// @match    *://chat.meta.stackexchange.com/rooms/*
// @require  https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant    GM_addStyle
// @grant    GM.getValue
// ==/UserScript==
//- The @grant directives are needed to restore the proper sandbox.

waitForKeyElements ("#chat img", loadHandling);

function loadHandling (jNode) {
    if (jNode[0].complete) {
        handleImgTag (jNode);
    }
    else {
        jNode.on ('load', handleImgTag);
    }
}
function handleImgTag (jNodeOrEvent) {
    var newImg;  //  will be jQuery node
    if (jNodeOrEvent instanceof jQuery) {
        newImg = jNodeOrEvent;
    }
    else {
        newImg = $(jNodeOrEvent.target);
    }
    console.log ("Found new image with width ", newImg.width () );
}

注意:建议调整传递给 waitForKeyElements 的 jQuery 选择器,以尽可能合理地缩小目标图像。

在浏览器范围内,可以使用 globalEventHandler 或 eventListeners。

但是因为用户脚本对 windowdocument 有一些不同的作用域,所以它不能按原样工作。这个范围问题与使用 web extensions(下一代 userscipts..)时相同,但至少它迫使我们多注意 DOM.

根据自己的实验,这里有一些针对用户脚本的解决方法。 通常我的实验会导致缺乏好奇心的“程序员”投反对票,所以别担心,玩得开心!

首先在用户脚本中延迟加载脚本,而不是加载事件。它很脏但有很大帮助,至少对于调试而言。

setTimeout(function(){    }, 3000)

要将事件处理程序加载到主文档中,我们必须创建一个元素并将其附加到主文档中 DOM。

在大多数情况下,问题的出现只是因为浏览器加载本地资源的速度更快,我们必须指定脚本在目标页面上的位置,或者它可能位于 DOM 的最顶部。 (意味着没有事件处理程序,我们不能通过名称调用 id,我们需要使用 getElementById 等等)

s = document.createElement("script")
s.innerText = "" // The events scripts
document.body.appendChild(s)

这里的好处是,脚本可以是外部的。通过加载外部脚本,浏览器会注意将其附加到 DOM,实际上如果 DOM 加载良好。在大多数情况下,只需执行此操作即可开始工作。

另一种方法是直接在目标 DOM.

的每个元素上设置 onchange 属性

如果元素已经存在,这是有效的。 (如果您通过更改 src 加载图像)。您也可以根据需要设置许多(隐藏的)元素以备后用并设置它们的属性。这有点多余,但要避免任何事件监听器。这是扁平的方法。它也可以在服务器端完成。

要在所有图像标签上设置 onchange,不知道它们的 id,我们可以使用 querySelectorAll,这在这种情况下非常有用,因为我们可以在其上使用 forEach。 (不同于 getElementsBytagName

document.querySelectorAll("img").forEach(function(element){
  element.setAttribute("onchange","handleImgTag()")
})

现在大家在一起了:

setTimeout(function(){
  // the querySelectorAll function encoded in base64
  var all = "ZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnaW1nJykuZm9yRWFjaChmdW5jdGlvbihlbGVtZW50KXsNCiAgZWxlbWVudC5zZXRBdHRyaWJ1dGUoJ29ubG9hZCcsJ2FsZXJ0KCknKQ0KfSk=" 
  s = document.createElement("script")
  // The events scripts, base64 decoded
  s.innerText = atob(all) + "" 
  document.body.appendChild(s)  // End of DOM, at trigger.

}, 1000) // Onloads sets after 1s.
<img src="http://icons.iconarchive.com/icons/martin-berube/flat-animal/64/pony-icon.png"></img>

<img src="" id="more"></img>

<button onclick="more.src='http://icons.iconarchive.com/icons/martin-berube/flat-animal/64/crab-icon.png'">LOAD MORE</button>

范围是好的用户脚本的关键。

尝试将所有脚本放在 DOM 末尾。祝你好运!