【问题标题】:Is there a way to uniquely identify an iframe that the content script runs in for my Chrome extension?有没有办法唯一标识内容脚本在我的 Chrome 扩展程序中运行的 iframe?
【发布时间】:2014-11-18 13:26:58
【问题描述】:

在我的 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 或从主页/首页收集数据,并将其发送回后台脚本(使用chrome.runtime.sendMessage。) 后台脚本反过来需要将数据存储在全局变量中,稍后在扩展本身中使用。

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

我可以通过运行以下命令来判断数据是来自IFRAME 还是来自首页:

//From the `content.js`
var isIframe = window != window.top;

我的想法是,如果我收集每个 IFRAME 的页面 URL,那么我应该能够将其用作唯一键来将数据存储在我的字典类型全局变量中:

//Again from content.js
var strUniqueIFrameURL = document.URL;

好吧,那是行不通的,因为两个或多个 IFRAMEs 可以有相同的 URL。

所以我最初的问题是——如何区分页面上的IFRAMEs? Chrome 是否为他们分配了一些唯一 ID 或某些东西?

【问题讨论】:

  • 重新表述您的问题。假设有一个页面上有 3 个<iframe>s,内容脚本都被注入其中,并且您想知道“这是标签 X 上第二个 <iframe> 中的内容脚本”。 iframe 是跨域的,使其更有趣。我理解正确吗?如果是,这是一个有趣的问题。
  • @Xan:是的,你是对的。除了iframes 可以是同源和跨源。 (我不是我的内容脚本注入的页面的作者,所以我假设这两种情况。)
  • 没有跨域问题,window.frameElementwindow.parent.document.querySelectorAll("iframe")很容易解决。但是你不能使用跨域 iframe 访问那些。
  • 等等!是可以解决的!由于内容脚本可以访问window.parent,不像框架自己的代码。
  • @Xan:嗯。谢谢。我得把它关到早上。现在为时已晚……想不通。会告诉你它是否有效。

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


【解决方案1】:

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

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

然后用这个ID将你所有的数据相关消息发送到后台。

【讨论】:

  • 谢谢。但每个 IFRAME 的此类 ID 必须保持不变。
  • 你“保持”什么不变?即使在 iframe 刷新之后?
  • 是的。如果页面重新加载,它们应该保持不变。由于后台脚本在页面重新加载后不会改变,如果我开始像你展示的那样组成 IFRAME id,当我将它们的数据存储在我的字典中时,它会在每次页面重新加载时创建重复记录。
  • 如果包含iframe的页面刷新了怎么办?您还需要通过这些刷新保持 id 的持久性吗?
  • 所以让我直截了当地说:你有两个 iframe(xy),具有相同的 URL,每个都应该在后台向 VAR_XVAR_Y 写入数据。当您刷新每个 iframe 时,它​​们会出现在同一个 URL 上(这意味着它们会加载相同的数据?)但您仍需要将它们绑定到它们的旧变量?
【解决方案2】:

您可以识别文档在 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);
   }
}

【讨论】:

  • 从快速测试来看,它确实适用于我“苦苦挣扎”的页面。谢谢!不过,我会尝试为嵌套的 iframe 修改它。我认为您的方法需要一些“递归”。
  • @c00000fd 太棒了!如果您确实改进了代码,请分享作为另一个答案。
  • @c00000fd 呃,我自己做的。有一些“递归”。
  • 对不起,我和你在不同的时区。我很欣赏你的工作!我不得不改变你的递归方法。
【解决方案3】:

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

所以回答我最初的问题,一旦我在页面中有IFRAME 索引,它将在该页面中唯一标识它(加上IFRAME 的URL。)

这是获取它的代码:

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 + "?";
}

【讨论】:

    猜你喜欢
    • 2014-11-03
    • 1970-01-01
    • 1970-01-01
    • 2011-09-28
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2011-11-02
    • 1970-01-01
    相关资源
    最近更新 更多