Chrome 扩展:向特定 iframe 中加载的页面发送消息
Chrome Extension: Sending a message to the page loaded in a specific iframe
我正在开发 Chrome 扩展以(除其他事项外)支持具有多个 iframe 的页面,每个 iframe 从其他域加载一个页面。我需要向加载这些 iframe 中特定一个的页面发送一条消息。顶级页面和 iframe 中的页面都有自己的内容脚本,因此可以使用完整的消息 API。
从首页开始,当我执行 chrome.runtime.sendMessage() 时,所有 iframe 都得到它(顶部 window 也是如此,但它的内容脚本很容易知道那个特定的消息不是为它设计的)。有什么方法可以定位这些 iframe 中的特定一个,或者让所需的 iframe 页面知道消息是针对它的吗?
请注意...
首页无法直接访问iframe页面中的任何内容,因为它们来自其他域。
首页知道每个框架中最初加载的 URL,但用户可能从那里导航,因此将目标 URL 作为 msg 参数用于接收脚本检查将不起作用。
我在这里明显遗漏了什么吗?
更新: @wOxxOm 的回答很有帮助,但我仍然不知道如何获取我需要的 frameIds。
更具体地说,我需要用这些 iframe 做两件事,这两件事都需要 frameId:
- 在每个 iframe 中注入一个脚本
- 将消息发送到特定的 iframe 以响应顶级页面上的用户操作
由于 iframe 是在用户工作时动态创建和删除的,因此所有这一切都变得复杂。
我的一个想法是首先使用 URL "about:blank?id=nnn" 加载每个新的 iFrame,其中 nnn 是相应 iframe 元素的 DOM id。这样,当我调用 getAllFrames() 时,我可以通过 URL 识别新的 iframe,并为每个 DOM id 构建 frameIds 查找。完成后,我可以加载真正的 URL,在加载后注入脚本。
这看起来很迂回,我希望我错过了一些支持 API 或其他直接的方法。
我确实找到了解决方案,但它非常间接。我希望这是清楚的;所有这些活动部件都是我理解的野兽的本性。
这是我最后做的事情:
- 为每个 iframe 添加了名称属性,与其 DOM id 相同。
- 当每个 iframe 中的页面加载时,全局内容脚本调用 chrome.runtime.sendMessage(),传递该名称,它可以作为 window.name.
访问
- 后台脚本获取该消息,该 iframe 的 frameId 为 sender.frameId,并调用 chrome.tabs.sendMessage(),传递 frameId 和 window 名称。
- top-level 页面的内容脚本从那些 window-name(也称为 iframe DOM id)/frameId 对构建一个查找对象。
- 当 top-level 页面的内容脚本想要向任何 iframe 页面发送消息时,它会在该查找对象中查找目标的 frameId,然后调用 chrome.runtime.sendMessage(),使用指示它用于特定 iframe 的消息类型,包括该 frameId。
- 作为响应,后台脚本使用 chrome.tabs.sendMessage() 将其发送到所请求的 iframe 的内容脚本,将 {frameId: request.frameId} 作为第三个参数传递,正如 wOxxOm 所建议的。
这在这里有效,但如果有更简单的方法,请务必告诉我。
我正在开发 Chrome 扩展以(除其他事项外)支持具有多个 iframe 的页面,每个 iframe 从其他域加载一个页面。我需要向加载这些 iframe 中特定一个的页面发送一条消息。顶级页面和 iframe 中的页面都有自己的内容脚本,因此可以使用完整的消息 API。
从首页开始,当我执行 chrome.runtime.sendMessage() 时,所有 iframe 都得到它(顶部 window 也是如此,但它的内容脚本很容易知道那个特定的消息不是为它设计的)。有什么方法可以定位这些 iframe 中的特定一个,或者让所需的 iframe 页面知道消息是针对它的吗?
请注意...
首页无法直接访问iframe页面中的任何内容,因为它们来自其他域。
首页知道每个框架中最初加载的 URL,但用户可能从那里导航,因此将目标 URL 作为 msg 参数用于接收脚本检查将不起作用。
我在这里明显遗漏了什么吗?
更新: @wOxxOm 的回答很有帮助,但我仍然不知道如何获取我需要的 frameIds。
更具体地说,我需要用这些 iframe 做两件事,这两件事都需要 frameId:
- 在每个 iframe 中注入一个脚本
- 将消息发送到特定的 iframe 以响应顶级页面上的用户操作
由于 iframe 是在用户工作时动态创建和删除的,因此所有这一切都变得复杂。
我的一个想法是首先使用 URL "about:blank?id=nnn" 加载每个新的 iFrame,其中 nnn 是相应 iframe 元素的 DOM id。这样,当我调用 getAllFrames() 时,我可以通过 URL 识别新的 iframe,并为每个 DOM id 构建 frameIds 查找。完成后,我可以加载真正的 URL,在加载后注入脚本。
这看起来很迂回,我希望我错过了一些支持 API 或其他直接的方法。
我确实找到了解决方案,但它非常间接。我希望这是清楚的;所有这些活动部件都是我理解的野兽的本性。
这是我最后做的事情:
- 为每个 iframe 添加了名称属性,与其 DOM id 相同。
- 当每个 iframe 中的页面加载时,全局内容脚本调用 chrome.runtime.sendMessage(),传递该名称,它可以作为 window.name. 访问
- 后台脚本获取该消息,该 iframe 的 frameId 为 sender.frameId,并调用 chrome.tabs.sendMessage(),传递 frameId 和 window 名称。
- top-level 页面的内容脚本从那些 window-name(也称为 iframe DOM id)/frameId 对构建一个查找对象。
- 当 top-level 页面的内容脚本想要向任何 iframe 页面发送消息时,它会在该查找对象中查找目标的 frameId,然后调用 chrome.runtime.sendMessage(),使用指示它用于特定 iframe 的消息类型,包括该 frameId。
- 作为响应,后台脚本使用 chrome.tabs.sendMessage() 将其发送到所请求的 iframe 的内容脚本,将 {frameId: request.frameId} 作为第三个参数传递,正如 wOxxOm 所建议的。
这在这里有效,但如果有更简单的方法,请务必告诉我。