通过Chrome扩展访问DOM元素

17

我正在尝试从网页中访问一些DOM元素:

<html>
  <button id="mybutton">click me</button>
</html>

我想通过Chrome扩展访问innerHTML(“click me”):

chrome.browserAction.onClicked.addListener(function(tab) {
    var button = document.getElementById("mybutton");
    if(button == null){
        alert("null!");
    }
    else{
        alert("found!");
    }
});
当我点击扩展时,弹出窗口显示:“null”。 我的manifest.json:
{
    "name": "HackExtension",
    "description": "Hack all the things",
    "version": "2.0",
    "permissions": [
    "tabs", "http://*/*"
    ],
    "background": {
    "scripts": ["contentscript.js"],
    "persistent": false
    },
    "browser_action": {
    "scripts": ["contentscript.js"],
    "persistent": false
    },
    "manifest_version": 2
}

2
可能是Chrome扩展程序 - 获取DOM内容的重复问题。 - Rob W
2个回答

35

解决方案: 您需要一个清单文件、一个后台脚本和一个内容脚本。在文档中并没有非常清楚地说明您需要使用它,以及如何使用它。要弹出完整 DOM,请参见此处。因为我很难找到一个完整的解决方案,实际上可以工作,而不仅仅是对于像我这样的新手无用的片段,所以我包含了一个具体的解决方案:

manifest.json

{
    "manifest_version": 2,
    "name":    "Test Extension",
    "version": "0.0",

    "background": {
        "persistent": false,
        "scripts": ["background.js"]
    },
    "content_scripts": [{
        "matches": ["file:///*"],
        "js":      ["content.js"]
    }],
    "browser_action": {
        "default_title": "Test Extension"
    },

    "permissions": ["activeTab"]
}

content.js

/* Listen for messages */
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
    /* If the received message has the expected format... */
    if (msg.text && (msg.text == "report_back")) {
        /* Call the specified callback, passing 
           the web-pages DOM content as argument */
    sendResponse(document.getElementById("mybutton").innerHTML);
    }
});

background.js

/* Regex-pattern to check URLs against. 
   It matches URLs like: http[s]://[...]stackoverflow.com[...] */
var urlRegex = /^file:\/\/\/:?/;

/* A function creator for callbacks */
function doStuffWithDOM(element) {
    alert("I received the following DOM content:\n" + element);
}

/* When the browser-action button is clicked... */
chrome.browserAction.onClicked.addListener(function(tab) {
    /*...check the URL of the active tab against our pattern and... */
    if (urlRegex.test(tab.url)) {
        /* ...if it matches, send a message specifying a callback too */
        chrome.tabs.sendMessage(tab.id, { text: "report_back" },
                                doStuffWithDOM);
    }
});

index.html

<html>
  <button id="mybutton">click me</button>
</html>

只需将index.html保存在某个地方,并将其作为扩展名加载到包含其他三个文件的文件夹中。打开index.html并点击扩展按钮,它应该会显示“click me”。


补充一下:内容脚本是可以访问网页 DOM 的脚本。如果需要,它可以将元素传递给另一个脚本。上面的示例使用了后台脚本,但也可以是弹出窗口。 - Bees
你介意解释一下"matches": ["file:///*"]这一行的含义吗?这不仅仅是针对本地文件吗? - max pleaner
1
它能够工作,但是一旦我在“browser_action”(manifest.json)中添加了"default_popup": "popup.html",它就停止工作了。 - Elia Weiss
安装扩展后,有没有一种方法可以监听DOM元素?我的意思是不使用onclick事件侦听器?我尝试在chrome.runtime.onInstalled.addListener中执行它,但没有起作用,或者我没有正确地执行它。 - mr.339

0
从Manifest V3开始,您的内容脚本将无法访问其他加载脚本生成的任何内容,并且使用内联代码的技巧,例如在<script>标签中嵌入您的代码,由于更严格的CSP规则而无法工作。这让我头痛不已,因为我无法弄清楚如何访问类似于React或Redux DevTools的库生成的DOM属性。
相反,您现在必须使用以下方式将脚本注入service_worker:
chrome.scripting.registerContentScripts([
  {
    id: 'inject',
    matches: ['<all_urls>'],
    js: ['inject.js'],
    runAt: 'document_end',
    world: 'MAIN'
  }
])

请注意使用 'MAIN' 属性,而不是默认的 'ISOLATED' 属性。然后在我的 inject.js 中进行任何操作,例如:
window.addEventListener('load', () => {
  findReact()
})

同时,您还需要将脚本添加到manifest.json中:

  "web_accessible_resources": [
    {
      "resources": ["inject.js"],
      "matches": ["<all_urls>"],
      "extension_ids": []
    }
  ],
  "externally_connectable": {
    "ids": ["*"]
  },

不确定是否需要使用 "externally_connectable"。您需要添加至少 "scripting" 权限。我使用 React DevTools 迁移作为我的来源 https://github.com/facebook/react/pull/25145


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接