有没有办法唯一标识内容脚本为我的Chrome扩展程序运行的iframe?

时间:2014-09-24 06:49:35

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

在我的Chrome扩展程序中,我将内容脚本注入页面内的所有IFRAMEs。这是manifest.json文件的一部分:

"content_scripts": [
    {
        "run_at": "document_end",
        "all_frames" : true,
        "match_about_blank": true,
        "matches": ["http://*/*", "https://*/*"],
        "js": ["content.js"]
    }
],

因此,包含多个IFRAMEs的单个网页最终会运行我注入content.js的多个副本。

content.js内的逻辑从每个注入的IFRAME中收集数据,或从主页/首页收集数据,然后将其发送回后台脚本(使用{ {1}}。)后台脚本又需要将数据存储在全局变量中,稍后在扩展本身中使用。

我面临的问题是应用程序需要区分从多个chrome.runtime.sendMessage收到的“数据”,因为我的数据收集方法可以在用户与页面交互时重复调用,因此我不能只需将后台脚本收到的数据“转储”到一个数组中。相反,我需要使用IFRAMEs类型的数据存储。

我可以通过运行以下内容来判断数据是来自dictionary还是来自首页:

IFRAME

我的想法是,如果我收集每个//From the `content.js` var isIframe = window != window.top; 的页面网址,那么我应该能够将它用作在我的字典类型全局变量中存储数据的唯一键:

IFRAME

嗯,这不会起作用,因为两个或更多//Again from content.js var strUniqueIFrameURL = document.URL; 可以使用相同的网址。

因此,我原来的问题 - 如何区分页面上的IFRAMEs?是否有一些Chrome分配给他们的唯一ID或某些标志?

3 个答案:

答案 0 :(得分:4)

您可以在iframe层次结构中标识文档的相对位置。根据页面的结构,这可以解决您的问题。

您的扩展程序可以访问window.parent及其框架。这应该可行,或者至少在测试用例中适用于我:

// Returns the index of the iframe in the parent document,
//  or -1 if we are the topmost document
function iframeIndex(win) {
  win = win || window; // Assume self by default
  if (win.parent != win) {
    for (var i = 0; i < win.parent.frames.length; i++) {
      if (win.parent.frames[i] == win) { return i; }
    }
    throw Error("In a frame, but could not find myself");
  } else {
    return -1;
  }
}

你可以修改它以支持嵌套iframe,但原则应该有效。

我自己很想做,所以你走了:

// Returns a unique index in iframe hierarchy, or empty string if topmost
function iframeFullIndex(win) {
   win = win || window; // Assume self by default
   if (iframeIndex(win) < 0) {
     return "";
   } else {
     return iframeFullIndex(win.parent) + "." + iframeIndex(win);
   }
}

答案 1 :(得分:1)

为了扩展@ Xan的answer,这是我的方法,即考虑其可能在其他IFRAME内嵌套的IFRAMEs索引。我将使用forward-iframe表示法,这意味着将首先给出父IFRAME索引,然后是子索引等。另外为了防止可能与浮点数混淆,我将使用下划线表示分隔符而不是点。

所以要回答我的原始问题,一旦我在页面中有IFRAME索引,它就会在该页面中唯一标识它(加上IFRAME的网址。)

以下是获取它的代码:

function iframeIndex(wnd)
{
    //RETURN:
    //      = "" for top window
    //      = IFrame zero-based index with nesting, example: "2", or "0_4"
    //      = "?" if error
    return _iframeIndex(wnd || window);     // Assume self by default
}

function _iframeIndex(wnd)
{
    var resInd = "";

    var wndTop = window.top;

    if(wnd == wndTop)
        return resInd;

    var wndPar = wnd.parent;

    if(wndPar != wndTop)
    {
        resInd = _iframeIndex(wndPar) + "_";
    }

    var frmsPar = wndPar.frames;
    for(var i = 0; i < frmsPar.length; i++)
    {
        if(frmsPar[i] == wnd)
            return resInd + i;
        }

    return resInd + "?";
}

答案 2 :(得分:0)

每次加载内容脚本时,您都可以使用时间戳和随机数的组合生成伪唯一ID,如下所示:

var psUid = (new Date()).getTime() + '_' + Math.random();

然后使用此ID将所有与数据相关的消息发送到后台。