如何访问网页 DOM 而不是扩展页面 DOM?
Posted
技术标签:
【中文标题】如何访问网页 DOM 而不是扩展页面 DOM?【英文标题】:How to access the webpage DOM rather than the extension page DOM? 【发布时间】:2011-05-30 18:06:51 【问题描述】:我正在编写一个 Chrome 扩展程序,并尝试在 popup.html 文件中单击按钮后立即在当前网页上覆盖 <div>
。
当我从 popup.html 中访问 document.body.insertBefore
方法时,它会覆盖弹出窗口上的 <div>
,而不是当前网页。
我是否必须在 background.html 和 popup.html 之间使用消息传递才能访问网页的 DOM?我想在 popup.html 中做所有事情,如果可能的话,我也想使用 jQuery。
【问题讨论】:
【参考方案1】:浏览器操作弹出窗口或 ManifestV2 后台脚本等扩展页面/脚本有自己的 DOM、document
、window
和 chrome-extension://
URL(使用扩展的 devtools for that part 来检查它)。 ManifestV3 service worker 没有任何 DOM/文档。
您需要content script 才能访问网页的 DOM 并与选项卡的内容进行交互。内容脚本将作为该页面的一部分在选项卡中执行,而不是作为扩展程序的一部分。
方法 1. 声明式
manifest.json:
"content_scripts": [
"matches": ["*://*.example.com/*"],
"js": ["contentScript.js"]
],
它会在页面加载时运行一次。之后,使用messaging,但请注意,它不能发送 DOM 元素、Map、Set、ArrayBuffer、类、函数等 - 它只能发送与 JSON 兼容的简单对象和类型,因此您需要手动提取所需数据并将其作为简单数组或对象传递。
方法2.程序化
ManifestV2:
使用chrome.tabs.executeScript 按需注入内容脚本。
此方法的回调接收内容脚本中最后一个表达式的结果,因此可用于提取必须与 JSON 兼容的数据,请参见上面的方法 1 注释。
manifest.json 中的必需权限:
最佳情况:"activeTab"
,适用于对用户操作的响应(通常是单击工具栏中的扩展图标)。安装扩展时不显示权限警告。
通常:"*://*.example.com/"
以及您想要的任何其他网站。
最坏的情况:"<all_urls>"
或 "*://*/"
、"http://*/"
、"https://*/"
- 当提交到 Chrome 网上应用店时,由于广泛的主机权限,所有这些都会将您的扩展程序置于超级缓慢的审核队列中。
ManifestV3与上述的区别:
使用chrome.scripting.executeScript。
manifest.json 中需要 permissions
:
"scripting"
- 强制
"activeTab"
- 理想情况,见上面 ManifestV2 的注释。
如果无法实现理想情况,请将允许的站点添加到 manifest.json 中的 host_permissions
。
【讨论】:
【参考方案2】:为了说明编程注入,让我们在单击浏览器操作时添加该 div。
ManifestV2
简单调用:
chrome.tabs.executeScript( code: `($ inContent1 )()` );
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.tabs.executeScript(
code: `($ inContent2 )($ JSON.stringify( foo: 'bar' ) )`
, ([result] = []) =>
if (!chrome.runtime.lastError)
console.log(result); // shown in devtools of the popup window
);
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,
;
这个例子使用了inContent
函数代码到字符串的自动转换,这里的好处是IDE可以应用语法高亮和linting。明显的缺点是浏览器会浪费时间来解析代码,但通常不到 1 毫秒,因此可以忽略不计。
ManifestV3
不要忘记 manifest.json 中的权限,有关更多信息,请参阅其他答案。
简单调用:
async function tabAddDiv()
const [tab] = await chrome.tabs.query(active: true, currentWindow: true);
await chrome.scripting.executeScript(
target: tabId: tab.id,
func: inContent1, // see inContent1 in ManifestV2 example above
);
注意:在 Chrome 91 或更早版本中,func:
应为 function:
。
带参数调用并接收结果
需要 Chrome 92,因为它实现了args
。
一个简单的例子:
res = await chrome.scripting.executeScript(
target: tabId: tab.id,
func: (a, b) => /* use a and b */ ,
args: ['foo', 'bar'],
);
现在让我们使用上面 ManifestV2 代码中的 inContent2
函数:
async function tabAddDiv()
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);
【讨论】:
此脚本将在后台或内容中进入哪个文件? 这个答案是主要答案的插图。请先阅读。 我已阅读,但您的回答不清楚在哪里 内容脚本是被注入的内容,因此您显然无法在被注入的内容中进行注入。我认为您应该再次阅读主要答案,也许还可以查看文档。以上是关于如何访问网页 DOM 而不是扩展页面 DOM?的主要内容,如果未能解决你的问题,请参考以下文章