Обнаружение новых изображений, загружаемых в DOM, обработчик событий загрузки jQuery не срабатывает

Я работаю над пользовательским скриптом, который делает разные вещи с изображениями.

Проблема в том, что иногда изображения добавляются на страницу ПОСЛЕ начальной загрузки, и эти изображения не обрабатываются моим пользовательским скриптом.

Мне нужен код в javascript / jQuery, который будет автоматически запускать функцию каждый раз, когда новое изображение загружается в браузер.

Вот что я пробовал:

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

Это не работает. Когда на страницу добавляется новое изображение (я использую chat.stackoverflow.com в качестве теста и отправляю новое сообщение, означающее, что мое изображение профиля снова добавляется на страницу, что не обрабатывается моим кодом), изображение не обрабатывается и с ним ничего не происходит.

Я пробовал поискать, но, похоже, не могу найти способ сделать это, возможно, из-за плохих условий поиска?

Есть ли событие или что-то, что я могу использовать в пользовательский скрипт Tampermonkey, который будет запускать функцию при добавлении нового изображения на страницу, на которой находится пользователь?

Обновлено:

Я не согласен с упомянутыми дубликатами, потому что речь идет именно об изображениях И использовании внутри пользовательского скрипта Tampermonkey. Кроме того, дубликаты имеют возраст 5-8 лет и могут не отражать передовой опыт или современные технологии.

Возможный дубликат (stackoverflow.com/questions/3219758/detect-changes-in-the-d‌ ом)

Ryan Wilson 01.05.2018 18:57

Возможный дубликат Обнаруживать изменения в DOM

Ason 01.05.2018 18:58
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
2
280
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

$('img').on('load',... не будет работать, потому что он рассылает анонимные обработчики событий на все образы существующий. Они никогда не привязываются к будущим, AJAX / динамически вставленным изображениям.

Правильная форма было бы будет: $('body').on ('load', 'img', handleImgTag);, КРОМЕСобытия load не всплывают.

Итак, вы должны использовать либо: методы (в основном 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.info ("Found new image with width ", newImg.width () );
}

Примечание: рекомендуется настроить селектор jQuery, переданный в waitForKeyElements, чтобы максимально сузить целевые изображения.

В итоге я использовал это в своем проекте - Imgur.com заблокирован, какие у меня варианты? - спасибо!

GrumpyCrouton 02.05.2018 14:59

В области браузера лучше всего использовать globalEventHandler или eventListeners.

Но поскольку у пользовательских скриптов есть несколько разных областей действия для window и document, он не работает как есть. Эта проблема с областью видимости такая же, как и при использовании веб-расширения (следующее поколение пользователей ...), но, по крайней мере, она заставляет нас много заботиться о DOM.

Вот несколько обходных путей для пользовательских скриптов после собственных экспериментов. Обычно мои эксперименты приводят к отрицательным голосам нелюбопытных «программистов», так что не беспокойтесь и получайте удовольствие!

Сначала вместо событий загрузки внутри пользовательского скрипта загружаются скрипты с задержкой. Это грязно, но очень помогает, по крайней мере, для отладки.

setTimeout(function(){    }, 3000)

Чтобы загрузить обработчики событий в основной документ, нам нужно создать элемент и добавить его в основную DOM.

В большинстве случаев проблемы возникают только потому, что браузеры загружают локальные ресурсы намного быстрее, мы должны указать, где сценарий должен быть на целевой странице, или он может быть расположен в самом верху DOM. (Это означает отсутствие обработчика событий, мы не можем вызывать id по их имени, нам нужно будет использовать getElementById и т. д. И т. Д.)

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

Хороший момент здесь то, что скрипт может быть внешним. Загружая внешние скрипты, браузеры позаботятся о том, чтобы добавить его в DOM, фактически, если DOM хорошо загружен. в большинстве случаев вещи начинают работать именно с этого действия.

Другой альтернативой является прямая установка атрибута onchange для каждого элемента целевой DOM.

Это действительно, если элементы уже существуют. (Если вы загружаете изображения, изменяя src). Вы также можете установить многие (скрытые) элементы по мере необходимости и установить их атрибуты. Это немного избыточно, но избегайте прослушивателей событий. Это плоский подход. Это тоже можно сделать на стороне сервера.

Чтобы установить 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. Удачи!

Я ценю ответ, но это было немного сложно понять, я также не совсем понимаю, как он должен обнаруживать новые изображения, загружаемые в DOM

GrumpyCrouton 02.05.2018 15:04

Используйте свой отладчик, смотрите теги изображений. у них обоих есть атрибут onload, устанавливаемый через одну секунду. Исходя из закодированной функции, добавленной к DOM. Давай!

NVRM 02.05.2018 15:08

Но это работает, только если я знаю информацию об изображении, верно?

GrumpyCrouton 02.05.2018 15:11

Нет, в данном случае нужен только сам элемент. Ничего больше. Я не знаю, как настроены ваши изображения, в этом случае, как только любой элемент img изменяется, он запускает функцию, и все. это точно так же, как и прослушиватели событий. Вы можете установить eventListeners точно так же, как только они будут добавлены в конец документа. Код выполняется только при декодировании base64. Вы также можете установить src скрипта вместо текста.

NVRM 02.05.2018 15:19

Релевантно: stackoverflow.com/questions/6432984/…

NVRM 02.05.2018 15:25

Этот подход не работает ни для полностью динамических страниц, ни для сценария чата, описанного OP. Кроме того, фрагмент кода выдает ошибку. И напрасное внедрение скриптов - плохая практика / рекомендация.

Brock Adams 02.05.2018 19:48

1 / в основном вы не читали 2 / Это отлично решает проблему OP. 3 / Нет ошибок в контексте документа, нет ошибок в Firefox, просто нет тела документа, forEach слишком продвинутый для вашего браузера. 4 / Вы вообще не читали, просто нужно подождать 1 секунду, прежде чем щелкнуть, это демонстрация для людей, которые уже знают javascript, а не для полных младенцев-нубов.

NVRM 03.05.2018 00:53

5 / Вы говорите о внедрении сценария и используете jquery 200 КБ для синтаксического анализа div ... Позвольте мне сказать вам кое-что: ваши знания отсутствуют. Покажите мне что-нибудь о «без нужды вводить скрипты - плохая практика / рекомендация». это не из доисторических веков. И после того, как я позволю вам открыть консоль javascript на больших сайтах, таких как twitter, youtube ... И снова давайте поговорим о плохой практике еще раз. ваш голос против. Это не кнопка «Я выхожу» ...

NVRM 03.05.2018 00:53

Другие вопросы по теме