浏览器扩展内容脚本,用于在加载特定元素后立即操作DOM



我正在开发一个浏览器扩展(MV2,Firefox(,它可以操作一个简单HTML页面的DOM。如果页面具有特定元素,则添加新的DOM元素。

如果我的内容脚本的run_at设置为"document_end";,DOM首先呈现给用户,然后我的内容脚本运行,然后它将新元素放在页面上——我添加的元素将比原始页面晚加载,所以它们明显地";眨眼;当被装载时。

我的目标是防止这种情况发生"眨眼";,这样我的元素就可以无缝地融入页面

页面实际上是一个基于HTML的单页应用程序——当你与应用程序交互时,页面会重新加载,UI元素会被缓存并保持在同一个位置,所以它们实际上永远不会从屏幕上消失,但我注入的元素会在一瞬间消失。需要注意的是,该应用程序也有不同布局的页面,我不需要在其中注入相同的元素,因此我需要在注入之前运行检测逻辑。

示例:

manifest.json:

{
"manifest_version": 2,
"name": "demo extension",
"version": "1",
"content_scripts": [
{
"matches": ["http://help.websiteos.com/websiteos/example_of_a_simple_html_page.htm" ],
"js" : ["main.js"],
"run_at": "document_end"
}
]
}

main.js:

var image = document.createElement("img");
image.style.position = "absolute";
image.style.top = 300;
image.style.left = 400;
image.src = "http://s3.amazonaws.com/pix.iemoji.com/images/emoji/apple/ios-12/256/thinking-face.png";
// dummy logic to determine whether the image should be injected
if( document.getElementsByClassName("img_whs1")[0] !== undefined ){
document.getElementsByTagName("body")[0].appendChild(image)
}

如果加载此,请导航到http://help.websiteos.com/websiteos/example_of_a_simple_html_page.htm,注入的图像将在DOM之后加载,因此您可以看到图像";眨眼";。如果刷新页面,图像会再次闪烁。


我的理解是,我需要有我的内容脚本来运行_at:;document_start";当然,所以我的内容脚本可以拦截特定DOM元素的加载,它将使用该元素来确定下一步要做什么。

我看到一个旧的StackOverflow回答提到了beforeLoad事件侦听器,但我找不到任何关于该事件的文档,也无法使其工作,我想它已经被弃用了。

使用突变观测器让我很困难——当脚本在document_start加载时,我唯一拥有的DOM元素就是HTML标记。当我调试下面的简单片段时,我看到body标记会一次加载它的所有内容,所以一旦我到达那里,就太晚了。

main2.js

const callback = (mutationList, observer) => {
debugger
}
const observer = new MutationObserver(callback);
const config = { attributes: true, childList: true, subtree: true };
observer.observe(document.getElementsByTagName("html")[0], config)

我应该采取什么方法?有没有一种方法可以让突变观察者在加载身体标签之前监听身体标签的变化?再一次,我想要实现的流程是:

  1. 我的内容脚本加载在document_start
  2. 一旦加载了特定的HTML元素,我的脚本就会根据该元素确定是否需要注入一些东西
  3. 必要时注入新元素(或者至少注入一个占位符,以防止闪烁,然后再执行其余的逻辑(

当DOM注入HEAD时,使用CSS隐藏所有元素,并在您自己的时间取消隐藏
这是我前面做的一个扩展的片段。

matches.js

const setVisibilityHidden = () => {
const style = document.createElement("style");
style.id = "visibility_hidden";
style.innerHTML = "* {visibility: hidden}";
document.head.insertBefore(style, null);
};
const resetVisibilityHidden = () => {
document.getElementById("visibility_hidden").remove();
};
const onMutation = (mutations) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeName == "HEAD") {
mo.disconnect();
setVisibilityHidden();
return;
}
}
}
}
const observe = () => {
mo.observe(document, {
subtree: true,
childList: true,
});
}
const mo = new MutationObserver(onMutation);
observe();

manifest.json

{
"name": "hoge",
"version": "1.0",
"manifest_version": 3,
"content_scripts": [
{
"js": [
"matches.js"
],
"matches": [
"<all_urls>"
],
"run_at": "document_start"
}
]
}

最新更新