Chrome 扩展如何将数据从内容脚本发送到 popup.html [英] Chrome Extension how to send data from content script to popup.html

查看:32
本文介绍了Chrome 扩展如何将数据从内容脚本发送到 popup.html的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道很多帖子都问过这个问题,但老实说我不明白.我是 JavaScript、Chrome 扩展和所有东西的新手,我有这门课.所以我需要制作一个插件,使用跨域请求来计算任何给定页面上的 DOM 对象.到目前为止,我已经能够使用 Chrome 扩展 API 实现这一点.现在的问题是我需要在我的 popup.html 页面上从 contentScript.js 文件中显示数据.我不知道该怎么做,我已经尝试阅读文档,但是在 chrome 中发送消息我就是不明白该怎么做.

以下是到目前为止的代码.

manifest.json

<代码>{"manifest_version":2,"name":"Dom 阅读器","description":"计数 Dom 对象","版本":"1.0",页面动作":{"default_icon":"icon.png","default_title":"Dom 阅读器","default_popup":"popup.html"},背景":{"脚本":["eventPage.js"],持久":假},内容脚本":[{"匹配":["http://pluralsight.com/training/Courses/*", "http://pluralsight.com/training/Au​​thors/Details/*", "https://www.youtube.com/用户/*", "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"]}],权限":[标签","http://pluralsight.com/*","http://youtube.com/*","https://sites.google.com/*",http://127.0.0.1:3667/*"]

popup.html

<标题>Dom阅读器</title><script src="jquery-1.10.2.js" type="text/javascript"></script><script src="popup.js" type="text/javascript"></script><身体><H1>Dom阅读器</H1><input type="submit" id="readDom" value="读取DOM对象"/><div id="domInfo">

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({动作:显示",tElements:总元素,Ifields:输入字段,bElements: buttonElement});

任何帮助将不胜感激,请避免我做的任何菜鸟:)

解决方案

尽管您的方向肯定是正确的(而且实际上已经接近尾声),但是您的代码中还是有一些 (imo) 不好的做法(例如注入一个整个库 (jquery) 用于这样一个微不足道的任务,声明不必要的权限,对 API 方法进行多余的调用等).
我没有亲自测试您的代码,但从快速概览来看,我相信更正以下内容可能会产生一个有效的解决方案(尽管不是非常接近最佳):

  1. ma​​nifest.json 中:更改内容脚本的顺序,将 jquery 放在首位.根据相关文档:

    <块引用>

    "js" [...] 要注入匹配页面的 JavaScript 文件列表.它们按在此数组中出现的顺序注入.

    (强调我的)

  2. contentscript.js 中:将 chrome.runtime.sendMessage({...}) 块移动内部onMessage 监听器回调.

<小时>

也就是说,这是我建议的方法:

控制流程:

  1. 内容脚本被注入到符合某些条件的每个页面中.
  2. 一旦注入,内容脚本就会向事件页面(即非持久性后台页面)发送一条消息,事件页面会将页面操作附加到选项卡上.
  3. 加载页面操作弹出窗口后,它会立即向内容脚本发送一条消息,询问所需的信息.
  4. 内容脚本处理请求并做出响应,以便页面操作弹出窗口可以显示信息.

<小时>

目录结构:

 根目录/|____img|_____icon19.png|_____icon38.png|_____manifest.json|_____background.js|_____content.js|_____popup.js|_____popup.html

<小时>

manifest.json:

<代码>{清单版本":2,"name": "测试扩展",版本":0.0",offline_enabled":真,背景": {持久":假,脚本":[background.js"]},内容脚本":[{"匹配": ["*://*.stackoverflow.com/*"],"js": ["content.js"],"run_at": "document_idle",all_frames":假}],页面动作":{"default_title": "测试扩展",//"default_icon": {//"19": "img/icon19.png",//"38": "img/icon38.png"//},"default_popup": "popup.html"}//不需要特殊权限...//权限":[]}

<小时>

background.js:

chrome.runtime.onMessage.addListener((msg, sender) => {//首先,验证消息的结构.if ((msg.from === 'content') && (msg.subject === 'showPageAction')) {//为请求选项卡启用页面操作.chrome.pageAction.show(sender.tab.id);}});

<小时>

content.js:

//通知后台页面//这个标签应该有一个页面操作.chrome.runtime.sendMessage({来自:'内容',主题:'showPageAction',});//侦听弹出窗口中的消息.chrome.runtime.onMessage.addListener((msg, sender, response) => {//首先,验证消息的结构.if ((msg.from === 'popup') && (msg.subject === 'DOMInfo')) {//收集必要的数据.//(对于您的特定要求`document.querySelectorAll(...)`//应该等同于 jquery 的 `$(...)`.)var domInfo = {总计:document.querySelectorAll('*').length,输入:document.querySelectorAll('input').length,按钮:document.querySelectorAll('button').length,};//直接响应发送者(popup),//通过指定的回调.响应(domInfo);}});

<小时>

popup.js:

//用新数据更新相关字段.const setDOMInfo = info =>{document.getElementById('total').textContent = info.total;document.getElementById('inputs').textContent = info.inputs;document.getElementById('buttons').textContent = info.buttons;};//一旦 DOM 准备好...window.addEventListener('DOMContentLoaded', () => {//...查询活动选项卡...chrome.tabs.query({活跃:真实,当前窗口:真}, 标签 =>{//...并发送对 DOM 信息的请求...chrome.tabs.sendMessage(标签[0].id,{来自:'弹出',主题:'DOMInfo'},//...还指定要调用的回调//从接收端(内容脚本).setDOMInfo);});});

<小时>

popup.html:

<头><script type="text/javascript" src="popup.js"></script><身体><h3 style="font-weight:bold; text-align:center;">DOM 信息</h3><table border="1" cellpadding="3" style="border-collapse:collapse;"><tr><td nowrap>元素总数:</td><td align="right"><span id="total">N/A</span></td></tr><tr><td nowrap>输入元素的数量:</td><td align="right"><span id="inputs">N/A</span></td></tr><tr><td nowrap>按钮元素的数量:</td><td align="right"><span id="buttons">N/A</span></td></tr>

I know this this has been asked in numerous posts but honestly I don't get them. I am new to JavaScript, Chrome Extensions and everything and I have this class assignment. So I need to make a plugin that would count DOM objects on any given page using Cross Domain Requests. I've been able to achieve this so far using Chrome Extension API's. 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.

following is the code so far.

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

 });
});
});

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 

});

Any help would be appreciated and please avoid any noobness I did :)

解决方案

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).
I did not test your code myself, but from a quick overview I believe that correcting the following could result in a working solution (although not very close to optimal):

  1. In manifest.json: Change the order of the content scripts, putting jquery first. According to the relevant docs:

    "js" [...] The list of JavaScript files to be injected into matching pages. These are injected in the order they appear in this array.

    (emphasis mine)

  2. In contentscript.js: Move the chrome.runtime.sendMessage({...}) block inside the onMessage listener callback.


That said, here is my proposed approach:

Control flow:

  1. A content script is injected into each page matching some criteria.
  2. Once injected, the content scripts send a message to the event page (a.k.a. non-persistent background page) and the event page attaches a page-action to the tab.
  3. As soon as the page-action popup is loaded, it sends a message to the content script, asking for the info it needs.
  4. The content script processes the request, and responds so the page-action popup can display the info.


Directory structure:

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


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>

这篇关于Chrome 扩展如何将数据从内容脚本发送到 popup.html的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆