Chrome 扩展如何将数据从内容脚本发送到 popup.html
Posted
技术标签:
【中文标题】Chrome 扩展如何将数据从内容脚本发送到 popup.html【英文标题】:Chrome Extension how to send data from content script to popup.html 【发布时间】:2013-11-29 23:03:14 【问题描述】:我知道这在很多帖子中都被问到过,但老实说我不明白。我是 javascript、Chrome 扩展和一切的新手,我有这个班级作业。 所以我需要制作一个插件,可以使用跨域请求计算任何给定页面上的 DOM 对象。 到目前为止,我已经能够使用 Chrome 扩展 API 实现这一目标。 现在的问题是我需要在我的 popup.html 页面上显示 contentScript.js 文件中的数据。 我不知道该怎么做我已经尝试阅读文档,但是在 chrome 中发送消息我就是不明白该怎么做。
以下是目前为止的代码。
manifest.json
"manifest_version":2,
"name":"Dom Reader",
"description":"Counts Dom Objects",
"version":"1.0",
"page_action":
"default_icon":"icon.png",
"default_title":"Dom Reader",
"default_popup":"popup.html"
,
"background":
"scripts":["eventPage.js"],
"persistent":false
,
"content_scripts":[
"matches":["http://pluralsight.com/training/Courses/*", "http://pluralsight.com/training/Authors/Details/*", "https://www.youtube.com/user/*", "https://sites.google.com/site/*", "http://127.0.0.1:3667/popup.html"],
"js":["domReader_cs.js","jquery-1.10.2.js"]
//"css":["pluralsight_cs.css"]
],
"permissions":[
"tabs",
"http://pluralsight.com/*",
"http://youtube.com/*",
"https://sites.google.com/*",
"http://127.0.0.1:3667/*"
]
popup.html
<!doctype html>
<html>
<title> Dom Reader </title>
<script src="jquery-1.10.2.js" type="text/javascript"></script>
<script src="popup.js" type="text/javascript"></script>
<body>
<H1> Dom Reader </H1>
<input type="submit" id="readDom" value="Read DOM Objects" />
<div id="domInfo">
</div>
</body>
</html>
eventPage.js
var value1,value2,value3;
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse)
if (request.action == "show")
chrome.tabs.query( active: true, currentWindow: true , function (tabs)
chrome.pageAction.show(tabs[0].id);
);
value1 = request.tElements;
);
popup.js
$(function ()
$('#readDom').click(function()
chrome.tabs.query(active: true, currentWindow: true, function (tabs)
chrome.tabs.sendMessage(tabs[0].id, action: "readDom");
);
);
);
内容脚本
var totalElements;
var inputFields;
var buttonElement;
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse)
if(request.action == "readDom")
totalElements = $("*").length;
inputFields = $("input").length;
buttonElement = $("button").length;
)
chrome.runtime.sendMessage(
action: "show",
tElements: totalElements,
Ifields: inputFields,
bElements: buttonElement
);
任何帮助将不胜感激,请避免我做的任何菜鸟:)
【问题讨论】:
【参考方案1】:尽管您的方向肯定是正确的(实际上已经接近尾声),但您的代码中有几个 (imo) 不好的做法(例如,为这样一个微不足道的任务注入整个库 (jquery),声明不必要的权限,对 API 方法进行多余的调用等)。 我自己没有测试您的代码,但从快速概述来看,我相信更正以下内容可能会产生一个可行的解决方案(尽管不是非常接近最优):
-
在 manifest.json 中:更改内容脚本的顺序,将 jquery 放在首位。根据the relevant docs:
"js" [...] 要注入匹配页面的 JavaScript 文件列表。这些是按照它们在此数组中出现的顺序注入的。
(强调我的)
-
在 contentscript.js 中:将 chrome.runtime.sendMessage(...) 块移动 inside
onMessage
listener回调。
也就是说,这是我提出的方法:
控制流程:
-
将内容脚本注入到符合某些条件的每个页面中。
注入后,内容脚本会向事件页面(也称为非持久性背景页面)发送消息,并且事件页面会将页面操作附加到选项卡。
加载页面操作弹出窗口后,它会立即向内容脚本发送一条消息,询问它需要的信息。
内容脚本处理请求并做出响应,以便页面操作弹出窗口可以显示信息。
目录结构:
root-directory/
|__img
|__icon19.png
|__icon38.png
|__manifest.json
|__background.js
|__content.js
|__popup.js
|__popup.html
manifest.json:
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"offline_enabled": true,
"background":
"persistent": false,
"scripts": ["background.js"]
,
"content_scripts": [
"matches": ["*://*.***.com/*"],
"js": ["content.js"],
"run_at": "document_idle",
"all_frames": false
],
"page_action":
"default_title": "Test Extension",
//"default_icon":
// "19": "img/icon19.png",
// "38": "img/icon38.png"
//,
"default_popup": "popup.html"
// No special permissions required...
//"permissions": []
background.js:
chrome.runtime.onMessage.addListener((msg, sender) =>
// First, validate the message's structure.
if ((msg.from === 'content') && (msg.subject === 'showPageAction'))
// Enable the page-action for the requesting tab.
chrome.pageAction.show(sender.tab.id);
);
content.js:
// Inform the background page that
// this tab should have a page-action.
chrome.runtime.sendMessage(
from: 'content',
subject: 'showPageAction',
);
// Listen for messages from the popup.
chrome.runtime.onMessage.addListener((msg, sender, response) =>
// First, validate the message's structure.
if ((msg.from === 'popup') && (msg.subject === 'DOMInfo'))
// Collect the necessary data.
// (For your specific requirements `document.querySelectorAll(...)`
// should be equivalent to jquery's `$(...)`.)
var domInfo =
total: document.querySelectorAll('*').length,
inputs: document.querySelectorAll('input').length,
buttons: document.querySelectorAll('button').length,
;
// Directly respond to the sender (popup),
// through the specified callback.
response(domInfo);
);
popup.js:
// Update the relevant fields with the new data.
const setDOMInfo = info =>
document.getElementById('total').textContent = info.total;
document.getElementById('inputs').textContent = info.inputs;
document.getElementById('buttons').textContent = info.buttons;
;
// Once the DOM is ready...
window.addEventListener('DOMContentLoaded', () =>
// ...query for the active tab...
chrome.tabs.query(
active: true,
currentWindow: true
, tabs =>
// ...and send a request for the DOM info...
chrome.tabs.sendMessage(
tabs[0].id,
from: 'popup', subject: 'DOMInfo',
// ...also specifying a callback to be called
// from the receiving end (content script).
setDOMInfo);
);
);
popup.html:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="popup.js"></script>
</head>
<body>
<h3 style="font-weight:bold; text-align:center;">DOM Info</h3>
<table border="1" cellpadding="3" style="border-collapse:collapse;">
<tr>
<td nowrap>Total number of elements:</td>
<td align="right"><span id="total">N/A</span></td>
</tr>
<tr>
<td nowrap>Number of input elements:</td>
<td align="right"><span id="inputs">N/A</span></td>
</tr>
<tr>
<td nowrap>Number of button elements:</td>
<td align="right"><span id="buttons">N/A</span></td>
</tr>
</table>
</body>
</html>
【讨论】:
哇!谢谢兄弟,现在检查你的方法我觉得我的代码产生了多少问题。非常感谢,这就像一个魅力。 :) 你好,对不起,我有一段时间没上,刚刚检查了你的评论。我不能接受任何答案。它说你需要 15 个声望点才能这样做。 你介意帮我解决一个非常相似的问题吗? ***.com/questions/34467627/…> 我目前对此的看法几乎就是您从这个答案中获得的代码。但我仍然无法让它工作,而且似乎无法在这件事上找到任何好的帮助。 为什么你在 popupjs 中使用chrome.tabs.sendMessage
,在 content.js 中使用 chrome.runtime.onMessage.addListener
为什么在 popupjs 中使用 .tabs
,在 content.js 中使用 .runtime
@hkm:因为这就是您发送和接收消息的方式。都在the docs。【参考方案2】:
您可以为此使用 localStorage。您可以将任何数据以哈希表格式存储在浏览器内存中,然后随时访问。我不确定我们是否可以从内容脚本访问 localStorage(它之前被阻止),尝试自己做。以下是如何通过后台页面进行操作(我首先将数据从内容脚本传递到后台页面,然后将其保存在 localStorage 中):
在 contentScript.js 中:
chrome.runtime.sendMessage(
total_elements: totalElements // or whatever you want to send
);
在 eventPage.js(你的背景页面)中:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse)
localStorage["total_elements"] = request.total_elements;
);
然后您可以使用 localStorage["total_elements"] 在 popup.js 中访问该变量。
也许您可以直接从现代浏览器中的内容脚本访问 localStorage。那么你就不需要通过你的后台页面传递数据了。
关于 localStorage 的精彩阅读:http://diveintohtml5.info/storage.html
【讨论】:
请不要推广使用已弃用的 chrome.extension.onRequest/sendRequest(顺便说一句,在执行之前不会加载非持久性背景页面)。请改用 chrome.runtime.*。 @ExpertSystem 如果您看到此类过时的信息,请建议/进行编辑。 @Xan:所以,你是 [Google-Chrome-Extension] 的继任者 :) 我不喜欢编辑别人的帖子(我觉得这太麻烦了)。此外,有这么多过时的教程和示例(至少在当时),我发现最好明确评论为什么使用.extension.xxx
是不好,而不是仅仅显示正确的方法(有些人可能认为这是“同样可行的选择”)。我猜这更多的是风格问题。继续努力!以上是关于Chrome 扩展如何将数据从内容脚本发送到 popup.html的主要内容,如果未能解决你的问题,请参考以下文章
Chrome 扩展程序 |如何在 CDN 的内容和后台脚本中包含库