Chrome 扩展如何将数据从内容脚本发送到 popup.html

我知道这个问题已经在很多帖子里被问到了,但是老实说我不明白。我对 JavaScript,Chrome 扩展和其他东西都是新手,我有这个课堂作业。 So I need to make a plugin that would count DOM objects on any given page using Cross Domain Requests. 到目前为止,我已经能够使用 Chrome 扩展 API 实现这一点。 Now the problem is I need to show the data on my popup.html page from the contentScript.js file. I don't know how to do that I've tried reading the documentation but messaging in chrome I just can't understand what to do.

以下是目前为止的代码。

宣言 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>

Event Page. 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"});


});
});
});

ContentScript

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


});

任何帮助都会受到感激,请避免我所做的任何菜鸟行为:)

105966 次浏览

您可以使用 localStorage 进行此操作。您可以将任何数据以哈希表格式存储在浏览器内存中,然后随时访问它。我不确定我们是否可以通过内容脚本访问 localStorage (它以前被阻止过) ,尝试自己来做。下面是如何通过后台页面实现这一点(我首先将数据从 content script 传递到后台页面,然后将其保存在 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 _ element”]访问 popup.js 中的变量。

也许您可以在现代浏览器中直接从内容脚本访问 localStorage。然后就不需要通过后台页面传递数据了。

关于 localStorage: http://diveintohtml5.info/storage.html的读物不错

Although you are definitely in the right direction (and actually pretty close to the end), there are several (imo) bad practises in your code (e.g. injecting a whole library (jquery) for such a trivial task, declaring unnecessary permissions, making superflous calls to API methods etc).
我没有亲自测试您的代码,但是从一个快速的概述来看,我相信纠正以下内容可以得到一个可行的解决方案(尽管不是非常接近最佳) :

  1. 宣言 Json中: 改变内容脚本的顺序,把 jquery 放在第一位。根据 相关文档:

“ js”[ ... ]要注入到匹配页面中的 JavaScript 文件列表。这些文件在这个数组中被注入 按照它们出现的顺序

(emphasis mine)

  1. Contentscript.js中: 移动 chrome.runtime.sendMessage({...})在里面onMessage侦听器回调。

话虽如此,我的建议是:

控制流程:

  1. 内容脚本被注入到每个匹配某些条件的页面中。
  2. 一旦注入,内容脚本就会向事件页面发送一条消息(也就是非持久性背景页面) ,事件页面将页面操作附加到选项卡。
  3. 页面动作弹出窗口一加载,它就向内容脚本发送一条消息,询问它所需要的信息。
  4. 内容脚本处理请求,并做出响应,这样页面操作弹出窗口就可以显示信息。

目录结构:

          root-directory/
|__img
|__icon19.png
|__icon38.png
|__manifest.json
|__background.js
|__content.js
|__popup.js
|__popup.html

Json:

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


"background": {
"persistent": false,
"scripts": ["background.js"]
},


"content_scripts": [{
"matches": ["*://*.stackoverflow.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": []
}

背景介绍:

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);
});
});

图片来源:

<!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>

我会给你一个简单的解决办法

The question is how to send message from content script to popup and not popup to content script

在弹出窗口中你必须从弹出窗口发送消息

document.addEventListener('DOMContentLoaded', function() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {type:"msg_from_popup"}, function(response){
alert(response)
});
});
}

在内容脚本中,你必须添加事件监听器,但问题是你必须使用 返回真值,这意味着你可以异步使用 sendResponse 如果你不提返回 true 它将同步工作,你必须立即返回 sendResponse 消息

chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
     

if(request["type"] == 'msg_from_popup'){
console.log("msg receive from popup");
            

sendResponse("msg received and sending back reply");// this is how you send message to popup
           

}
return true; // this make sure sendResponse will work asynchronously
        

}
);