搜尋

首頁  >  問答  >  主體

從擴充功能存取網頁的`window`/DOM/HTML

我正在編寫一個 Chrome 擴展程序,並嘗試在 popup.html 文件中單擊按鈕後立即在當前網頁上覆蓋

當我從 popup.html 存取 document.body.insertBefore 方法時,它會覆寫彈出視窗上的

,而不是目前網頁。

我是否必須在background.html 和popup.html 之間使用訊息傳遞才能存取網頁的DOM?我想在 popup.html 中完成所有操作,如果可能的話也使用 jQuery。

P粉046878197P粉046878197401 天前632

全部回覆(2)我來回復

  • P粉296080076

    P粉2960800762023-10-19 08:17:05

    使用程式註入來新增該 div 的擴充彈出腳本的一些範例。

    清單V3

    不要忘記在manifest.json中新增權限,請參閱其他答案以獲取更多資訊。

    • 簡單呼叫:

      (async () => {
        const [tab] = await chrome.tabs.query({active: true, currentWindow: true});
        await chrome.scripting.executeScript({
          target: {tabId: tab.id},
          func: inContent1,
        });
      })();
      
      // executeScript runs this code inside the tab
      function inContent1() {
        const el = document.createElement('div');
        el.style.cssText = 'position:fixed; top:0; left:0; right:0; background:red';
        el.textContent = 'DIV';
        document.body.appendChild(el);
      }
      

      注意:在 Chrome 91 或更早版本中,func: 應為 function:

    • 使用參數呼叫並接收結果

      需要 Chrome 92,因為它實作了 args

      範例1:

      res = await chrome.scripting.executeScript({
        target: {tabId: tab.id},
        func: (a, b) => { return [window[a], window[b]]; },
        args: ['foo', 'bar'],
      });
      

      範例2:

      (async () => {
        const [tab] = await chrome.tabs.query({active: true, currentWindow: true});
        let res;
        try {
          res = await chrome.scripting.executeScript({
            target: {tabId: tab.id},
            func: inContent2,
            args: [{ foo: 'bar' }], // arguments must be JSON-serializable
          });
        } catch (e) {
          console.warn(e.message || e);
          return;
        }
        // res[0] contains results for the main page of the tab 
        document.body.textContent = JSON.stringify(res[0].result);
      })();
      
      // executeScript runs this code inside the tab
      function inContent2(params) {
        const el = document.createElement('div');
        el.style.cssText = 'position:fixed; top:0; left:0; right:0; background:red';
        el.textContent = params.foo;
        document.body.appendChild(el);
        return {
          success: true,
          html: document.body.innerHTML,
        };
      }
      

    清單V2

    • 簡單呼叫:

      // uses inContent1 from ManifestV3 example above
      chrome.tabs.executeScript({ code: `(${ inContent1 })()` });
      
    • 使用參數呼叫並接收結果:

      // uses inContent2 from ManifestV3 example above
      chrome.tabs.executeScript({
        code: `(${ inContent2 })(${ JSON.stringify({ foo: 'bar' }) })`
      }, ([result] = []) => {
        if (!chrome.runtime.lastError) {
          console.log(result); // shown in devtools of the popup window
        }
      });
      

      此範例使用 inContent 函數的程式碼自動轉換為字串,這樣做的好處是 IDE 可以應用語法突出顯示和 linting。明顯的缺點是瀏覽器會浪費時間來解析程式碼,但通常不到 1 毫秒,因此可以忽略不計。

    回覆
    0
  • P粉600402085

    P粉6004020852023-10-19 00:39:30

    問題:擴充頁面(彈出視窗、選項、MV2 中的背景頁面等)與網頁分離,它們有自己的DOM、document、< code>window 和chrome-extension:// URL。

    解決方案:使用內容腳本存取網頁頁面或與其內容互動。

    • 內容腳本在網頁中執行,而不是在擴充功能中執行。
    • 內容腳本預設是隔離的,請參閱如何在頁面上下文中執行程式碼(也稱為主世界)。
    • 不要在擴充功能頁面中載入內容腳本。

    方法1.宣告式

    manifest.json:

    "content_scripts": [{
      "matches": ["*://*.example.com/*"],
      "js": ["contentScript.js"]
    }],
    

    它將在頁面載入時運行一次。之後,請使用訊息傳遞

    警告!它不能傳送 DOM 元素、Map、Set、ArrayBuffer、類別、函數等。它只能發送與 JSON 相容的簡單物件和類型,因此您需要手動提取所需的資料並將其作為簡單陣列或物件傳遞。

    方法 2. 程式化

    • ManifestV3

      在擴充腳本(如彈出視窗)可根據需要將內容腳本/函數注入標籤。

      此方法的結果是內容腳本中的最後一個表達式,因此可用於擷取資料。資料必須與 JSON 相容,請參閱上面的警告。

      manifest.json 中所需的權限

      • 「腳本」 - 強制;
      • "activeTab" - 理想場景,適合對使用者操作的回應(通常是點擊工具列中的擴充圖示)。安裝擴充功能時不顯示任何權限警告。

      如果理想情況不可能,請將允許的網站新增至manifest.json 中的host_permissions

      • 「*://*.example.com/」 以及您想要的任何其他網站。

      • """*://*/" 這些會將您的擴充功能置於Chrome 線上應用程式商店中超慢審核佇列中由於廣泛的主機權限。

    • ManifestV2 與上述的差異:

    回覆
    0
  • 取消回覆