【问题标题】:Open multiple tabs in a loop and transfer different data to each tab's content script循环打开多个选项卡并将不同的数据传输到每个选项卡的内容脚本
【发布时间】:2016-01-28 13:45:36
【问题描述】:

我的扩展是这样工作的:

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

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

ma​​nifest.json:

{
  "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.html

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

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

contentscript.js

document.addEventListener("DOMContentLoaded", function(event) {
   pasteData();
});
    var i;

/////////
function pasteData(){

        chrome.storage.local.get('storageObjectName', function (data) {
              chrome.extension.onMessage.addListener(function(message,sender,sendResponse){

            var testData = data;

            // article title
            document.getElementById('data_name').value = testData["storageObjectName"].articles[0]["articleTitle"];
            // article perex
            document.getElementById('data_perex').value = testData["storageObjectName"].articles[0]["articlePerex"];
            // article author
            document.getElementById('data_source').value = testData["storageObjectName"].articles[0]["articleAuthor"];
            // article url
            document.getElementById('data_url').value = testData["storageObjectName"].articles[0]["articleUrl"];
            // article date
            document.getElementById('data_valid_from').value = testData["storageObjectName"].articles[0]["articleDate"];

          });
}

【问题讨论】:

  • 你好,我用我所有的代码编辑了任务。
  • 您不需要chrome.storage.local 将所需的数据传递给内容脚本。我可以通过sendMessage告诉你一个更简单的方法,你可以吗?
  • @wOxxOm 非常感谢。我还需要将 X 变量发送到新窗口...

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


【解决方案1】:

问题中的代码有一些问题:

  1. 在调用 .set 回调之前在 popup.js 中打开选项卡(它与所有 chrome. API 回调一样是异步的)
  2. 内容脚本读取数据但从不使用它,因为没有消息发送到onMessage 侦听器,因此它的回调永远不会被调用。
  3. manifest.json 都定义了内容脚本自动注入规则,并且 popup.js 通过 executeScript 注入它。
  4. 为了让executeScript 在未明确单击弹出图标的选项卡上工作,应在 manifest.json 的 "permissions" 键中声明 URL。

其实这个任务不需要把数据保存到chrome.storage.local
让我们使用简单的消息传递。


  • ma​​nifest.json,假设内容脚本应该只注入executeScript

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

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

      或使用"&lt;all_urls&gt;" 可以将脚本注入任何站点。

  • popup.js,假设articleArray的所有项目都应该打开并且url定义在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/*"]["&lt;all_urls&gt;"](尽量避免使用后者,因为它过于宽松,用户不会喜欢您的扩展程序可以访问和修改他们访问的所有站点上的数据的警告)。
  • 使用code: 参数指定内联代码(如果它是短/简单的)
  • 否则使用file: 参数指定单独的内容脚本文件
  • 确保代码中的最后一个表达式或语句的计算结果为简单的数字/布尔值或字符串值(它将被传递给回调),否则使用JSON.stringify(obj)
  • DOM 元素不能直接序列化;使用Array.mapinnerHTML或其他方法仅提取您需要的信息
  • 回调会收到一个结果数组,第一个元素对应主页面,其他的都是frames/iframes

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

【讨论】:

  • 非常感谢!!完美运行!!!但我有最后一个问题。如何将此脚本与“实际选项卡”中的选择数据结合起来?
  • 感谢您的提示。我会尝试将此应用于我的数组,但仍然收到错误:Uncaught Error: Invalid value for argument 1. Property 'function': Unexpected property.
  • 它可以使用几个 cmets,这就是我要说的。
  • 非常感谢。我正确获取数据,但实际上我编辑了 forEach 脚本并获取了 contentscript“未定义”值...我的代码:.... function doSomething(data){ var articleArray = data; articleArray.forEach(function(article) { ....
  • 下面的新答案...:-/
猜你喜欢
  • 1970-01-01
  • 2013-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-06
  • 1970-01-01
相关资源
最近更新 更多