为什么我不能将此消息传递到在选项卡中运行的所有帧? [英] Why can't I deliver this message to all of the frames running in a tab?

查看:105
本文介绍了为什么我不能将此消息传递到在选项卡中运行的所有帧?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

主题



我正在创建一个镀铬扩展,需要我将邮件从我的活动页面发送到在特定框架上运行的内容脚本



当单击上下文菜单选项时,将调用消息传递操作。所说的选项只有当焦点中的元素被可编辑 onClickedrel =nofollow> chrome.contextMenus API。我需要将其发送到包含元素的最内层框架。 (所以我可以通过访问 document.activeElement 对象来修改其内容)



截至Chrome 41,您是可以通过将选项参数的 frameID 参数的值填充到< a href =https://developer.chrome.com/extensions/tabs#method-sendMessage =nofollow> chrome.tabs.sendMessage() 功能。



但是,Chrome 41目前处于测试阶段,所以我显然无法期望此功能与我的用户浏览器兼容。



因此,我计划向标签中的所有框架发送消息(通过在具有 all_frames 属性设置为true)。一旦进入内容脚本,我可以通过将 window.location.href 的值与我期望的值进行比较来查看是否正确的框架。 p>

问题



看起来像是对事件侦听器或消息传递的方式有误解。文档很清楚, chrome.tabs.sendMessage()应该向标签中的每个帧发送一条消息,但似乎只能有一个单个 chrome.runtime.onMessage()每个消息调用事件监听器,即使有很多监听器被注册。实际上被调用哪一个似乎以某种方式由页面的初始加载决定。



这可以用我的扩展名的简化版本进行演示:



manifest.json:

  {
manifest_version:2,

name:Demo,
description:这是一个演示,
version:1.0,

permission:[
< all_urls>,
contextMenus
],

background:{
page background.html,
persistent:false
},

content_scripts:[{
matches:[< all_urls> ],
js:[content.js],
all_frames:true
}]
}
/ pre>

background.html:

 <!DOCTYPE文本/ HTML> 
< html>
< head>
< textarea id =temp>< / textarea>
< script src =event.js>< / script>
< / head>
< body>
< / body>
< / html>

event.js:

  chrome.contextMenus.onClicked.addListener(requestHandler); 
chrome.contextMenus.create({
title:Click Me !!,
contexts:[editable],
id:1
});

函数requestHandler(info,tab)
{
chrome.tabs.sendMessage(tab.id,{destination:info.frameUrl});

//这应该被发送到标签中的每个框架
}

content.js:

  chrome.runtime.onMessage.addListener(handleRequest); 

alert(你好,我是:+ window.location.host);
函数handleRequest(message)
{
alert(您尝试发送消息到:+ message.destination);
alert(我是:+ window.location.href);
}

如果您访问了许多框架的页面,如 youtube ,您应该注意到以下行为:




  • 在初始加载页面时,您会收到许多提醒,表明有多个框架正在加载(全部带有监听器)


  • 当您单击上下文菜单选项时,只会弹出一个警报,指示只有一个帧接收到消息


  • 接收消息的帧在上下文选项的多次点击中保持不变,但在刷新页面时可能会发生更改。这表示最初加载帧的顺序决定了哪个帧将要获取您的消息。







所以,我如何确保我正在尝试谈话的框架实际上得到我的消息,而不使用 frameID 选项仅在chrome 41中可用?



起初我以为我可以从内容脚本发回一个响应,指示消息是否到达正确的地方。我可以在事件页面中继续这样做一段时间,直到我收到一条告诉我停止的消息,但是像我之前所说的那样,消息总是似乎转到同一帧,直到页面被刷新,所以这种方法对我而言没有任何作用。



其他详细信息



其他我注意到的是,如果有两帧一个具有相同来源的网页,例如plus.google.com,两个框架都将响应该消息,如果这是消息发生的交付帧的集合。所以收件人似乎是基于起源而不是一些独特的框架ID。



这是一个链接到我所说现象的视频:





请注意,我最初来自:youtube.com,accounts.google .com,plus.google.com和client6.google.com,但只有客户6收到我的消息

解决方案


您的 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);
});
});


Subject

I am creating a chrome extension that requires me to send a message from my event page to a content script that is running on a specific frame

The message passing operation is invoked when a context menu option is clicked. Said option is only available when the element in focus is categorized as editable by the chrome.contextMenus API. I need to send it to the innermost frame in which the element is contained. (so I can modify its contents by accessing the document.activeElement object)

As of Chrome 41, you are able to send a message to a specific frame by filling the value of the frameID parameter of the options argument to the chrome.tabs.sendMessage() function.

However, Chrome 41 is currently in beta, so I obviously cant expect this feature to be compatible with my users' browsers.

So, I planned of sending a message to all of the frames in the tab (by registering listeners on a content script that had the all_frames property set to true) . Once inside the content script I could check to see if this was the right frame or not by comparing the value of window.location.href with the value I am expecting.

Problem

It appears as If I had a misconception about the way that either event listeners or message passing works. The documentation makes it pretty clear that chrome.tabs.sendMessage() is supposed to send a message to every frame in the tab, but it appears as if there can only be a single chrome.runtime.onMessage() event listener invoked per message, even if there are many listeners registered. Which one actually gets invoked appears to be somehow dictated by the initial loading of the page.

This can be demonstrated with a simplified version of my extension:

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
     }]
}

background.html:

<!DOCTYPE text/html>
<html>
 <head>
  <textarea id="temp"></textarea>
  <script src="event.js"></script>
 </head>
 <body>
 </body>                                                                                                                                                                   
</html>

event.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
}

content.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);
}

If you visit a page with many frames, like youtube you should notice the following behavior:

  • You get many alerts upon the initial loading of the page, indicating that there are many frames being loaded (all with listeners)

  • When you click the context menu option, only a single alert pops up, indicating that only a single frame received the message

  • The frame that receives the message remains constant throughout multiple clicks of the context option, but is likely to change when you refresh the page. This indicates that the order in which the frames are initially loaded determines which frame is going to get your message.


So, how can I assure that the frame I am trying to talk with actually gets my message, without resorting to the frameID option that's only available in chrome 41?

At first I thought I could send a response back from the content script, indicating whether or not the message went to the right place. I could just keep doing this in a while loop in the event page until I got back a message telling me to stop, but like I said earlier, the message always seems to go to the same frame until the page is refreshed, so this approach does nothing for me.

Additional Details

Something else I have noticed is that if there are two frames on a page with the same origin, like plus.google.com for example, both frames will respond to the message, if that is the frame set that the message happened to get delivered to. So, the recipient seems to be based on origin rather than by some unique frame ID.

Here is a link to a video I took of the phenomena I am speaking of:

Notice that I got alerts initially from: youtube.com, accounts.google.com, plus.google.com and client6.google.com, but only client6 got my message

解决方案

Your chrome.runtime.onMessage event listener calls alert. This method blocks the runtime until the dialog is closed. For some reason, this also prevents Chrome from correctly triggering the onMessage events in other frames (reported as crbug.com/456482).

A work-around is to use console.log for debugging instead of alert, or wrap the code within setTimeout to asynchronously process the onMessage event. E.g.

chrome.runtime.onMessage.addListener(function(message) {
    setTimeout(function() {
        alert('Message: ' + message);
    });
});

这篇关于为什么我不能将此消息传递到在选项卡中运行的所有帧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆