Нет API, кроме тех, которые вы упомянули. Единственный дополнительный подход заключается в подключении Node.prototype.appendChild
и нескольких других методов для изменения DOM в контексте страницы . Естественно, вам также придется подключать такие вещи, как сеттеры innerHTML / outerHTML.
Переопределение методов-прототипов может нарушить работу некоторых сайтов, которые делают подобные вещи низкого уровня.
Теоретически, по крайней мере, так что будьте осторожны.
Вот упрощенный контент-скрипт, который перехватывает несколько распространенных методов:
const eventId = chrome.runtime.id + Math.random().toString(36);
const script = document.createElement('script');
script.textContent = `(${eventId => {
let reportingEnabled = true;
// only simple data can be transferred, not DOM elements, not functions, etc.
const sendReport = detail => dispatchEvent(new CustomEvent(eventId, {detail}));
const makeHook = (name, fn) =>
function () {
if (reportingEnabled) sendReport({name, phase: 'pre'});
const res = fn.apply(this, arguments);
if (reportingEnabled) sendReport({name, phase: 'post'});
return res;
};
const {appendChild} = Node.prototype;
Node.prototype.appendChild =
Element.prototype.appendChild = makeHook('appendChild', appendChild);
const {append} = Element.prototype;
Element.prototype.append = makeHook('append', append);
const innerHTML = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
innerHTML.set = makeHook('innerHTML', innerHTML.set);
Object.defineProperties(Element.prototype, {innerHTML});
}})('${eventId}')`;
document.documentElement.appendChild(script);
script.remove();
window.addEventListener(eventId, e => {
console.log(e.detail);
});
Очевидно, вам нужно подключить все другие методы, такие как removeChild, insertBefore и т. д. on.
Элементы DOM не могут быть переданы посредством обмена сообщениями из контекста страницы в сценарий содержимого. Переносимы только тривиальные типы, такие как строки, числа, логические, нулевые и массивы / объекты, которые состоят из таких типов. Однако для существующего элемента DOM есть хитрость: вы можете передать его индекс [...document.getElementsByTagName('*')].indexOf(element)
, а затем сразу использовать его как document.getElementsByTagName('*')[index]
. Для ShadowDOM вам придется создать рекурсивный индексатор.