2012-08-01 103 views
2

是指具有相同的JavaScript在两个网页和一个iframe运行的技术,为described in this answeruserscript的两个实例如何在帧之间进行通信?

例如,假设您在domain_A.com有此页:

<html> 
<body> 
    <iframe src="http://domain_B.com/SomePage.htm"></iframe> 
</body> 
</html> 

如果您设置@match指令是这样的:

// @match http://domain_A.com/* 
// @match http://domain_B.com/* 

然后您的脚本将运行两次 - 一次在主页面上,一次在iframe上,就像它是独立页面一样。


什么是有脚本的两个实例相互沟通的选项?

这将需要同步的实例。例如,只有在网页脚本实例完成后,iframe脚本实例才能执行其任务,反之亦然。

回答

2

这两个脚本实例可以使用postMessage()相互通信。关于:

这将需要同步的实例,所以例如有一个iframe只能在网页完成后执行其任务,反之亦然。

这正是this, stunningly brilliant, answer中显示的内容。 ;)
Chrome has bugs in how it presents frames/iframes to extensions(Chrome用户的脚本是带有自动生成清单的扩展)。
因此,要解决这些错误,您必须注入注入的代码,该代码调用postMessage()

以下脚本显示了方法。它:

  • 运行在iframe和包含页面中。
  • 处理跨域iframes。
  • 它表明具有下述逻辑脚本间控制:
    1. 容器页面设置以监听来自的IFRAME消息。
    2. iframe设置为侦听来自容器页面的消息。
    3. iframe将第一条消息发送到容器页面。
    4. 当容器页面收到该消息时,它会发送另一条消息回iframe。

安装此脚本:

// ==UserScript== 
// @name  _Cross iframe, cross-domain, interscript communication 
// @include  http://fiddle.jshell.net/9aQv5/* 
// @include  http://www.puppylinux.com/ 
// ==/UserScript== 

console.log ("Script start..."); 

if (window.top === window.self) { 
    console.log ("Userscript is in the MAIN page."); 

    //--- Setup to process messages from the GM instance running on the iFrame: 
    window.addEventListener ("message", receiveMessageFromFrame, false); 
    console.log ("Waiting for Message 1, from iframe..."); 
} 
else { 
    console.log ("Userscript is in the FRAMED page."); 

    //--- Double-check that this iframe is on the expected domain: 
    if (/puppylinux\.com/i.test (location.host)) { 
     window.addEventListener ("message", receiveMessageFromContainer, false); 

     //--- Send the first message to the containing page. 
     sendMessageFromAnIframe (
      "***Message 1, from iframe***", "http://fiddle.jshell.net" 
     ); 
     console.log ("Waiting for Message 2, from containing page..."); 
    } 
} 

function receiveMessageFromFrame (event) { 
    if (event.origin != "http://www.puppylinux.com") return; 

    console.log ('The container page received the message, "' + event.data + '".'); 

    //--- Send message 2, back to the iframe. 
    sendMessageToAnIframe (
     "#testIframe", 
     "***Message 2, from the container page***", 
     "http://www.puppylinux.com" 
    ); 
} 

function receiveMessageFromContainer (event) { 
    if (event.origin != "http://fiddle.jshell.net") return; 

    console.log ('The iframe received the message, "' + event.data + '".'); 
} 

/*--- Because of bugs in how Chrome presents frames to extensions, we must inject 
    the messaging code. See bug 20773 and others. 
    frames, top, self.parent, contentWindow, etc. are all improperly undefined 
    when we need them. See Firefox and other browsers for the correct behavior. 
*/ 
function sendMessageFromAnIframe (message, targetDomain) { 
    var scriptNode   = document.createElement ('script'); 
    scriptNode.textContent = 'top.postMessage ("' + message 
          + '", "' + targetDomain + '");' 
          ; 
    document.body.appendChild (scriptNode); 
} 

function sendMessageToAnIframe (cssSelector, message, targetDomain) { 
    function findIframeAndMessageIt (cssSelector, message, targetDomain) { 
     var targetIframe = document.querySelector (cssSelector) 
     if (targetIframe) { 
      targetIframe.contentWindow.postMessage (message, targetDomain); 
     } 
    } 
    var scriptNode   = document.createElement ('script'); 
    scriptNode.textContent = findIframeAndMessageIt.toString() 
          + 'findIframeAndMessageIt ("' + cssSelector 
          + '", "' + message 
          + '", "' + targetDomain + '");' 
          ; 
    document.body.appendChild (scriptNode); 
} 

console.log ("Script end"); 


然后参观this test page at jsFiddle

你会在JavaScript控制台中看到这一点:

 
Script start... 
Userscript is in the MAIN page. 
Waiting for Message 1, from iframe... 
Script end 
Script start... 
Userscript is in the FRAMED page. 
Waiting for Message 2, from containing page... 
Script end 
The container page received the message, "***Message 1, from iframe***". 
The iframe received the message, "***Message 2, from the container page***". 
+0

布洛克,我刚刚从假期回来,看到你的答案。非常感谢,我会详细研究并尝试将其应用于我的案例。 – Exilas 2012-08-20 23:31:15

+0

@Exilas,好的。祝你好运。 – 2012-08-21 00:52:35

+0

1)截至目前,postMessage可用于Chrome吗?你提到代码需要注入,因为chrome扩展有问题。这仍然是这样吗? 2)作为在postscript中使用postMessage的原始问题的扩展,是否有可能让网站本身拦截在postscript中使用postMessage? – Edge 2015-03-13 09:37:44

相关问题