在循环中打开多个选项卡,并将不同的数据传输到每个选项卡的内容脚本

时间:2015-10-28 16:49:58

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

我的扩展程序是这样的:

  • 用户在扩展程序的弹出窗口中按Run按钮
  • 弹出脚本从活动标签收集文章链接,标题等数据 问题#1:我该如何实现?
  • 使用循环中收集的数据打开多个标签
  • 将内容脚本注入每个打开的标签
  • 每个打开的标签页的内容脚本应该从该数组元素中接收自己的数据 问题2:我该如何实现?

目前,我使用chrome.storage.local存储整个收集数据数组,并希望将每个内容脚本传递给循环索引变量,以便内容脚本从{{1}读取正确的元素}。

的manifest.json:

chrome.storage.local

popup.html

{
  "manifest_version": 2,
  "name": "My Extension",
  "description":"My article Extension",
   "version": "1.0",
  "background": {
    "scripts": ["model/background.js"],
    "persistent": true
  },
  "content_scripts": [{
    "run_at": "document_start",
     "matches": ["myurl"],
      "js": ["model/contentscript.js", "model/jquery_2.1.4.min.js"]
    }],
  "browser_action": {
    "default_popup": "template/popup.html",
    "default_icon": "template/images/icon.png",
    "default_title": "Start copy articles"
  },
  "icons": {
    "16":"template/images/icon.png",
    "48":"template/images/icon.png",
    "128":"template/images/icon.png"
    },
 "permissions": [
    "tabs",
    "activeTab",
    "storage",
    "cookies"
 ]
}

popup.js ,它不会收集真实数据;使用测试文章阵列

<!doctype html>

<head>
    <title>Tapito Chrome extenstion</title>
    <meta charset="utf-8">
</head>
<body>
    <p>Variable</p><br>
    <input type="text" value="" placehorlder="10" id="variable1" /><br>
    <button id="runScript">Run</button>
    <script src="popup.js" type="text/javascript"></script>

    <div id="debugMode">

    </div>
</body>

contentscript.js

function StartPastingArticles(){
  var count = 3;

  // test array
  var articleArray = {
        articles: [
          {articleTitle: "title 1", articlePerex: "perex 1", articleAuthor: "author 1", articleDate: "date 1", articleUrl: "url 1"},
          {articleTitle: "title 2", articlePerex: "perex 2", articleAuthor: "author 2", articleDate: "date 2", articleUrl: "url 2"},
          {articleTitle: "title 3", articlePerex: "perex 3", articleAuthor: "author 3", articleDate: "date 3", articleUrl: "url 3"},
          {articleTitle: "title 4", articlePerex: "perex 4", articleAuthor: "author 4", articleDate: "date 4", articleUrl: "url 4"},
          {articleTitle: "title 5", articlePerex: "perex 5", articleAuthor: "author 5", articleDate: "date 5", articleUrl: "url 5"},
        ],
        options: [
          {time: '10', startDate: 'today'}
        ]
    };

        // actualy sending data via storage
        chrome.storage.local.set({'storageObjectName': articleArray}, function () {});

        var x = 1;
        while (x < count){
          chrome.tabs.create({'url': 'myurl'}, function(tab){
            openWindow(tab.id);
          });
          x++;
        }
}
    // open new window and run script
    function openWindow(tabId){
        chrome.tabs.executeScript(tabId,{file:"contentscript.js"},function(){
        });
    }
 // callback for popup htm
document.getElementById("runScript").addEventListener("click", function(e){
    StartPastingArticles();
})

1 个答案:

答案 0 :(得分:0)

问题中的代码存在一些问题:

  1. 在调用.set回调之前,在popup.js中打开选项卡(它与所有chrome. API回调一样异步)
  2. 内容脚本读取数据但从不使用它,因为没有消息发送到onMessage侦听器,因此永远不会调用它的回调。
  3. manifest.json定义内容脚本自动注入规则AND popup.js通过executeScript注入它。
  4. executeScript处理未明确点击弹出图标的标签页,应在manifest.json&#39; s "permissions"键中声明网址。
  5. 实际上,对于此任务,无需将数据保存到chrome.storage.local 让我们使用简单的消息传递。

    • manifest.json ,假设内容脚本只能注入executeScript

      1. 删除"content_script"部分。
      2. 添加executeScript的权限:

        "permissions": [
            ................
            "*://possibleurl1/*",
            "http://possibleurl2/*",
            "https://possibleurl3/*",
        ]
        

        或使用"<all_urls>"能够在任何网站上注入脚本。

    • popup.js ,假设应打开articleArray的所有项目并在articleUrl属性中定义网址:

      articleArray.articles.forEach(function(article) {
          chrome.tabs.create({url: article.articleUrl, active: false}, function(tab) {
              var tabId = tab.id;
              chrome.tabs.executeScript(tabId, {
                  file: "contentscript.js",
                  runAt: "document_start"
              }, function(result) {
                  chrome.tabs.sendMessage(tabId, {action: "article", data: article});
              });
          });
      });
      

      所以1)创建一个标签而不激活它,2)注入内容脚本,2)将当前处理过的文章数据的消息发送到该标签。

    • <强> contentscript.js

      chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
          if (msg.action == "article") {
              // make a local copy because msg will be garbage-collected
              var article = msg.data; 
              document.addEventListener("DOMContentLoaded", function() {
                  pasteData(article);
              });
          }
      });
      
      function pasteData(article) {
          document.getElementById('data_name').value = article.articleTitle;
          document.getElementById('data_perex').value = article.articlePerex;
          document.getElementById('data_source').value = article.articleAuthor;
          document.getElementById('data_url').value = article.articleUrl;
          document.getElementById('data_valid_from').value = article.articleDate;
      }
      

    从活动标签收集数据使用chrome.tabs.executeScript注入内容脚本:

    • 确保您拥有"permissions": ["activeTab"]["http://allowed.url/path/*"]["<all_urls>"](尽量避免使用后者,因为它过于宽松,用户不会喜欢警告您的扩展程序可以访问和修改他们访问的所有网站上的数据。
    • 使用code:参数指定内联代码(如果它是短/简单
    • 使用file:参数
    • 指定单独的内容脚本文件
    • 确保代码中的最后一个表达式或语句求值为简单数字/布尔值或字符串值(它将传递给回调),否则使用JSON.stringify(obj)
    • DOM元素不能直接序列化;使用Array.mapinnerHTML或其他方法仅提取您需要的信息
    • 回调将收到一系列结果,第一个元素对应主页面,其他元素对应于帧/ iframe

    chrome.tabs.executeScript({code:" \
        JSON.stringify( \
            [].map.call(document.querySelectorAll('.article'), function(article) { \
                return { \
                    title: article.querySelector('.title').textContent, \
                    url: article.querySelector('a').href \
                }; \
            }) \
        )"
    }, function(results) {
        var actualData = JSON.parse(results[0]);
        doSomething(actualData);
    });