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

时间:2013-11-16 15:10:11

标签: javascript jquery html google-chrome google-chrome-extension

我知道这已经在很多帖子中被问到了,但说实话,我没有得到它们。我是JavaScript,Chrome扩展程序以及所有内容的新手,我有这个课程作业。 所以我需要创建一个插件,使用跨域请求计算任何给定页面上的DOM对象。 到目前为止,我已经能够使用Chrome Extension API实现这一目标。 现在问题是我需要在contentScript.js文件中的popup.html页面上显示数据。 我不知道该怎么做我已经尝试阅读文档但是在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"});

 });
});
});

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 

});

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

2 个答案:

答案 0 :(得分:144)

虽然你肯定是在正确的方向(并且实际上非常接近结束),但是你的代码中存在几个(imo)不良实践(例如,为这样一个简单的任务注入一个完整的库(jquery),声明不必要的权限,对API方法进行超级调用等) 我自己没有测试你的代码,但是从快速概述我认为纠正以下内容可能会产生一个有效的解决方案(尽管不是非常接近最佳):

  1. manifest.json 中:更改内容脚本的顺序,首先放置jquery。根据 the relevant docs

      

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

    (强调我的)

  2. contentscript.js 中:移动 chrome.runtime.sendMessage({...})阻止阻止 { {1}}监听器回调。


  3. 那就是说,这是我提议的方法:

    控制流程:

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

    5. 目录结构:

      onMessage

      的manifest.json:

                root-directory/
                 |_____img
                       |_____icon19.png
                       |_____icon38.png
                 |_____manifest.json
                 |_____background.js
                 |_____content.js
                 |_____popup.js
                 |_____popup.html
      

      background.js:

      {
        "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": []
      }
      

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

      popup.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.html:

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

答案 1 :(得分:4)

您可以使用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