为什么我无法将此消息传递到选项卡中运行的所有帧
Why can't I deliver this message to all of the frames running in a tab?
Subject
我正在创建一个 chrome 扩展程序,要求我将消息从我的活动页面发送到在特定框架上运行的内容脚本
单击上下文菜单选项时,将调用消息传递操作。仅当焦点元素被 chrome.contextMenus
API 分类为editable
时,该选项才可用。我需要将其发送到包含该元素的最内层框架。(所以我可以通过访问document.activeElement
对象来修改其内容(
从 Chrome 41 开始,您可以通过将 options
参数的 frameID
参数的值填充到 chrome.tabs.sendMessage()
函数来向特定帧发送消息。
但是,Chrome 41目前处于测试阶段,因此我显然不能期望此功能与用户的浏览器兼容。
因此,我计划向选项卡中的所有帧发送一条消息(通过在将all_frames
属性设置为 true 的内容脚本上注册侦听器(。进入内容脚本后,我可以通过将window.location.href
的值与我期望的值进行比较来检查这是否是正确的帧。
问题
似乎我对事件侦听器或消息传递的工作方式有误解。该文档非常清楚地表明,chrome.tabs.sendMessage()
应该向选项卡中的每一帧发送一条消息,但似乎每条消息只能调用一个chrome.runtime.onMessage()
事件侦听器,即使注册了许多侦听器。实际调用哪一个似乎在某种程度上是由页面的初始加载决定的。
这可以通过我的扩展的简化版本来证明:
manifest.json:
{
"manifest_version":2,
"name":"Demo",
"description":"This is a demonstration",
"version":"1.0",
"permissions":[
"<all_urls>",
"contextMenus"
],
"background": {
"page":"background.html",
"persistent":false
},
"content_scripts":[{
"matches":["<all_urls>"],
"js":["content.js"],
"all_frames":true
}]
}
背景.html:
<!DOCTYPE text/html>
<html>
<head>
<textarea id="temp"></textarea>
<script src="event.js"></script>
</head>
<body>
</body>
</html>
事件.js:
chrome.contextMenus.onClicked.addListener(requestHandler);
chrome.contextMenus.create({
"title":"Click Me!!",
"contexts":["editable"],
"id":"1"
});
function requestHandler(info, tab)
{
chrome.tabs.sendMessage(tab.id, {"destination":info.frameUrl});
//this should get sent to every frame in the tab
}
内容.js:
chrome.runtime.onMessage.addListener(handleRequest);
alert("Hi, i'm: " + window.location.host);
function handleRequest(message)
{
alert("You tried to send a message to: " + message.destination);
alert("I am: " + window.location.href);
}
如果您访问包含多个框架的页面(例如 youtube(,您应该注意到以下行为:
- 在
页面初始加载时,您会收到许多警报,指示正在加载许多帧(所有帧都带有侦听器(
单击上下文菜单选项时,仅弹出单个警报,表示只有一个帧收到消息
接收消息的框架在多次单击上下文选项时保持不变,但在刷新页面时可能会更改。这表示帧最初加载的顺序决定了哪个帧将接收消息。
那么,我
如何确保我尝试与之交谈的框架确实能收到我的信息,而无需求助于仅在chrome 41中可用的frameID
选项?
起初,我以为我可以从内容脚本中发回响应,指示消息是否转到正确的位置。我可以在事件页面中循环一段时间内继续这样做,直到我收到一条消息告诉我停止,但就像我之前说的,消息似乎总是转到同一帧,直到页面刷新,所以这种方法对我没有任何作用。
其他详细信息
我注意到的另一件事是,如果页面上有两个具有相同来源的框架,例如 plus.google.com,如果这是消息碰巧传递到的框架集,则两个框架都将响应消息。因此,接收方似乎基于原点,而不是基于某个唯一的帧 ID。
这是我拍摄的关于我所说的现象的视频的链接:
- https://www.youtube.com/watch?v=WVz8zBVqgIw&feature=youtu.be
请注意,我最初收到来自以下方面的警报:youtube.com、accounts.google.com、plus.google.com 和 client6.google.com,但只有 client6 收到了我的消息
您的chrome.runtime.onMessage
事件侦听器调用alert
。此方法阻止运行时,直到对话框关闭。出于某种原因,这也会阻止 Chrome 在其他帧中正确触发 onMessage 事件(报告为 crbug.com/456482(。
解决方法是使用 console.log
而不是 alert
进行调试,或者将代码包装在 setTimeout
中以异步处理onMessage
事件。
chrome.runtime.onMessage.addListener(function(message) {
setTimeout(function() {
alert('Message: ' + message);
});
});
- MobileFirst:在客户端运行计时器作业-最佳选项
- 使用自定义选项从控制台运行JSlint
- Chrome扩展插件:runtime.last运行tabs.get/tabs.remove时出错:没有id为0的选项卡
- 如何在并行选项卡中运行彗星聊天
- 将运行时中的最大缩放选项更改为 ol.在开放层 3 中查看
- 如何使setInterval在浏览器选项卡处于焦点时运行
- 在iPad上运行时,Mobile Safari中即将切换选项卡的Pagehide事件不会触发
- 如何:让javascript在浏览器选项卡更改时运行
- Chrome扩展-重定向当前选项卡后重新运行扩展脚本
- 若在两个不同的选项卡中打开同一个页面,如何防止javascript运行两次
- 自定义Div滑块运行过快,但仅当从另一个浏览器选项卡返回时
- 为什么我无法将此消息传递到选项卡中运行的所有帧
- Grunt为任务设置选项,并使用新值运行该任务
- 根据特定选项卡中的元素运行 .each()
- 首次运行时未发出首选项
- 在后台选项卡上运行画布
- 您能否检查 Web 应用程序是否已在另一个浏览器选项卡上运行
- 仅在选项卡处于活动状态时运行内容脚本循环
- 在浏览器关闭选项卡或浏览器退出上运行方法
- $window.unload 中的 Post 方法从未调用更改 url,关闭选项卡,但在关闭浏览器时运行