检测正在加载到DOM中的新图像,jQuery load event-handler不会触发

时间:2018-05-01 16:54:59

标签: javascript jquery tampermonkey

我正在开发一个用图片做各种事情的用户脚本。

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

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

这就是我的尝试:

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

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

我试过四处寻找,但我似乎无法找到办法,也许是因为搜索条件不好?

是否有可以在 Tampermonkey用户脚本中使用的事件或其他内容,当用户所在页面上添加新图片时,该用户将运行该功能?

编辑:

我不同意上面提到的重复项,因为这是关于图像的,并且在Tampermonkey用户内部使用。此外,重复项还有5到8年的历史,可能无法反映最佳实践或当前技术。

2 个答案:

答案 0 :(得分:1)

$('img').on('load',...无效,因为它会将匿名事件处理程序发送到所有现有图像上。他们从未接受过未来的AJAX /动态插入图像。

的正确格式为:$('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.stackoverflow.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 () );
}

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

答案 1 :(得分:-1)

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

但是因为用户脚本对windowdocument有一些不同的范围,所以它不能正常工作。使用web extensions(下一代usercipts ..),这个范围问题是相同的,但至少它迫使我们更多地关注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加载图像)。您也可以根据需要设置许多(隐藏)元素并设置其属性。这有点多余,但避免任何事件侦听器。这是扁平的方法。它也可以在服务器端完成。

要在不知道其ID的情况下为所有图片代码设置onchange,我们可以使用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端。祝你好运!