且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在内容脚本加载到Chrome扩展程序之前,如何避免出现样式错误的内容?

更新时间:2023-12-05 09:17:58

时尚的chrome扩展名使用以下步骤解决了此问题:

Stylish chrome extension solved this problem using the following steps:


  1. 将状态缓存在后台页面中脚本变量并将其消息发送回内容脚本,该脚本将在开始时要求提供数据。

  2. (可选)从 chrome.webNavigation.onCommitted 发生在页面开始加载之前,有时甚至在内容脚本运行之前,因此此方法只是附加方法测量。不过,您可以将其设为唯一的方法,例如使用setlival在后台页面脚本中。

  3. 使用 persistent:true 背景页面。可以说,在这种通信方案中,这是唯一避免非持久事件页面可靠地避免 FOUC 的方法需要一些时间来加载。

  4. document_start

    执行内容脚本时,文档为空,没有头,没有正文。此时,时尚扩展(其功能是样式注入)仅在< html> 下直接添加一个样式元素。

  1. Cache the state in a background page script variable and message it back to the content script which asks for the data on its start.
  2. Optionally send a message to the content script from chrome.webNavigation.onCommitted which occurs before the page started loading, sometimes even before a content script runs so this method is just an additional measure. You can make it the sole method, though, by sending the same message several times using e.g. setInterval in the background page script.
  3. Use a "persistent": true background page. Arguably, it's the only method to avoid FOUC reliably in this communication scenario as non-persistent event pages need some time to load.
  4. Declare the content script to be injected at "document_start".
    When the content script executes the document is empty, no head, no body. At this point Stylish extension, its function being style injection, simply adds a style element directly under <html>.

在您的情况下,还需要执行其他步骤:

In your case an additional step is needed:


  1. 使用MutationObserver进行处理页面加载时的页面(示例性能信息)。

  1. Use MutationObserver to process the page as it's being loaded (example, performance info).

manifest.json:

manifest.json:

"background": {
    "scripts": ["background.js"]
},
"content_scripts": [
    {
        "js": ["contents.js"]
        "matches": ["<all_urls>"],
        "run_at": "document_start",
        "all_frames": true,
    }
],

内容脚本:

var gotData = false;

chrome.runtime.sendMessage({action: 'whatDo'}, doSomething);

chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
    if (msg.action == 'doSomething') {
        doSomething(msg);
    }
});

function doSomething(msg) {
    if (gotData || !msg || !msg.data)
        return;

    gotData = true;

    new MutationObserver(onMutation).observe(document, {
        childList: true, // report added/removed nodes
        subtree: true,   // observe any descendant elements
    });

    function onMutation(mutations, observer) {
        // use the insanely fast getElementById instead of enumeration of all added nodes
        var elem = document.getElementById('targetId');
        if (!elem)
            return;
        // do something with elem
        .............
        // disconnect the observer if no longer needed
        observer.disconnect();
    }
}

背景页面脚本:

var state;

chrome.storage.sync.get({state: true}, function(data) {
    state = data.state;
});

chrome.storage.onChanged.addListener(function(changes, namespace) {
    if (namespace == 'sync' && 'state' in changes) {
        state = changes.state.newValue;
    }
});

chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
    if (msg.action == 'whatDo') {
        sendResponse({action: 'doSomething', data: state});
    }
});

chrome.webNavigation.onCommitted.addListener(function(navDetails) {
    chrome.tabs.sendMessage(
        navDetails.tabId,
        {action: 'doSomething', data: state},
        {frameId: navDetails.frameId}
    );
});

重复消息传递,一个简单的示例,它不检查消息是否已处理:

Repeated messaging, a simple example that doesn't check if the message was processed:

chrome.webNavigation.onCommitted.addListener(function(navDetails) {
    var repetitions = 10;
    var delayMs = 10;
    send();

    function send() {
        chrome.tabs.sendMessage(
            navDetails.tabId,
            {action: 'doSomething', data: state},
            {frameId: navDetails.frameId}
        );
        if (--repetitions)
            setTimeout(send, delayMs);
    }
});