如何在 iFrame 正文标签上设置 jQuery data() 并从 iFrame 内部检索它?

Posted

技术标签:

【中文标题】如何在 iFrame 正文标签上设置 jQuery data() 并从 iFrame 内部检索它?【英文标题】:How to set jQuery data() on an iFrame body tag and retrieve it from inside the iFrame? 【发布时间】:2013-05-17 08:35:36 【问题描述】:

我无法在我创建的 iFrame 上设置 data()

这就是我正在做的:

  // options > my configuration object
  // options.src = eg "path/foo.html"
  // options.id = uuid
  // options.parent = $(elem)
  // options.param = JSON object 

  newHTML = document.createElement("iframe");
  newHTML.setAttribute("src", options.src);
  newHTML.setAttribute("frameborder", 0);
  newHTML.setAttribute("seamless", "seamless");
  newHTML.setAttribute("data-id", options.id);

  newParentElement = options.parent.parent()[0];
  options.parent.replaceWith( newHTML ); 

  // select 
  newRootElement = newParentElement.querySelectorAll(
    '[data-id="'+options.id+'"]'
  );

  // add configuration 
  $( newRootElement[0] ).load(function () 
    var newElement = $(this);
    if (options.param) 
      newElement.contents().find("body").attr("foo","bar").data("config", options.param);
    
  );

当我查看我的 iframe 和它的正文标签时,attr("foo") 已正确设置,我也可以像这样对其进行控制台:

  console.log(newElement.contents().find("body").attr("foo"));

但是当我尝试使用data()data("config") 来控制config 时,就像这样:

  console.log(newElement.contents().find("body").data("config"));

它总是返回undefined

问题: 为什么不能在 iFrame 上设置 jQuery data()?还是我做错了什么?

感谢您的帮助!

【问题讨论】:

options.param 是一个有效的字符串吗?为什么不为所有脚本使用 jQuery 语法?会容易得多:) jQuery 不会将数据与元素本身一起存储。它只是将id 与元素一起存储。数据本身存储在jQuery.cache 中。如果您使用父级的 jQuery 对象从 iframe 外部设置数据,则设置的数据 存在于父级中,并且无法使用 .datajQuery 对象检索框架。那是因为这两个 jQuery 对象不共享它们的 .cache 对象。 @t.niese:啊。谢谢。你能把它作为一个答案,以便我检查一下吗? 我已经在 FF、Safari 和 Chrome 中测试了您的代码,并且可以正常工作。这是一个小提琴jsbin.com/atezot/3/edit。确保在设置数据之前不要检索数据。 【参考方案1】:

jQuery 不将数据与元素本身一起存储,而是在jQuery.cache 中。

在 jQuery 代码中你有这部分:

jQuery.expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" )

正如您所见,每个 jQuery 加载都会创建一个独特的扩展。

expando 用作属性来存储带有 DOM 元素的标识符。

当您在元素中使用.data(key,value) 存储数据时,jQuery 会执行以下步骤:

    检查是否存在与element[jQuery.expando] 中的元素一起存储的id,如果没有,它会创建一个唯一的id。 检查是否存在带有jQuery.cache[id] 的条目,如果没有则创建一个空对象来存储该元素的数据。

因此,如果您调用 .data(key,value),数据将存储在您使用的 jQuery 实例定义的窗口中。

如果您在parent 中有一个jQuery 对象,在iframe 中有一个对象,则由于随机数,它们有两个不同的expandos。如果您在 iframe 的元素上从父 jQuery 对象调用 .data(),则会使用父级的 expando 并将数据存储在父级中。如果您随后使用 iframe jQuery,然后在与 iframe 的 jQuery 之前相同的元素上调用 .data,则不会找到任何数据,因为它一方面具有不同的 expando,另一方面数据存储在父窗口。

所以如果你想在 iframe 中设置数据,你应该使用 iframes jQuery 对象。 $('iframe')[0].contentWindow.jQuery("body").data( ... ) 设置数据,然后可以再次从 iframe 内部检索该数据,因为您使用相同的 jQuery 对象来设置和读取数据。

编辑 一个额外的重要说明。因为数据是与使用的 jQuery 实例一起存储的,所以您不应该使用 jQuery 在另一个上下文中存储数据。 jQuery 有一个清理方法,当您使用 jQuery 删除元素时会调用该方法,该方法会删除事件侦听器并从 jQuery.cache 中删除数据。但是,如果您使用 jQuery 为另一个上下文中的元素存储数据,则此清理方法将失败(例如,如果您在 iframe 中加载另一个页面)。因此,只有在重新加载父级时,数据才会被释放。

【讨论】:

@frequent 我对这个问题的回答可能对你也有用:javascript: Can data be passed bi-directionally through an iframe? 酷。一旦 iframe 正常工作,我就会做这样的事情 :-) 再次感谢!【参考方案2】:

通过向$(selector, scope) 提供第二个参数,确保您的 jQuery 选择器在相关范围内查找。

$(function() 
    var scope = $('iframe')[0].contentWindow.document; // <iframe>
    $('body', scope).data('id', 'some id');            // set data on body of iframe 
    console.log($('body', scope).data('id'));          // ==> 'some id'
);

这是一个小提琴,我成功地将数据设置到 iframe 的主体然后检索它:http://jsbin.com/ecenij/1/edit

【讨论】:

酷。 scope 很方便。在上面尝试,是否可能是时间问题。 @Vadim 您不应该以这种方式设置数据或附加事件侦听器,因为如果您在 iframe 中加载另一个页面(然后在iframe 将在内存中,直到父窗口重新加载。)

以上是关于如何在 iFrame 正文标签上设置 jQuery data() 并从 iFrame 内部检索它?的主要内容,如果未能解决你的问题,请参考以下文章

无法通过 jQuery 访问 iFrame 的类的高度

在Firefox中将焦点设置为iframe正文/内容?

如何使用正文中的 min-height 属性设置 iframe 的高度?

使用 jQuery,我想知道 Gmail 的新电子邮件组合 iframe 的正文中何时发生事件

jQuery怎么给iframe的src赋值

怎么通过js或jquery获取iframe里面video 标签,这么做是不是可行?