4

この回答で説明されているように、同じ JavaScript を Web ページと iframe の両方で実行する手法を参照してください。

たとえば、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/*

次に、スクリプトが 2 回実行されます。1 回はメイン ページで、もう 1 回はスタンドアロン ページであるかのように iframe で実行されます。


スクリプトの 2 つのインスタンスが相互に通信するためのオプションは何ですか?

これは、インスタンスを同期するために必要です。たとえば、iframe スクリプト インスタンスは、Web ページ スクリプト インスタンスが完了した後にのみタスクを実行し、その逆も同様です。

4

1 に答える 1

7

2 つのスクリプト インスタンスは、 を使用して相互に通信できますpostMessage()。それにかんする:

これは、インスタンスを同期するために必要です。たとえば、iframe のタスクを Web ページのタスクが完了した後にのみ実行する場合や、その逆の場合です。

それがこの他の回答に示されているものです。
ただし、 Chrome にはフレーム/iframe を拡張機能に表示する方法にバグがあります。そのため 、これらのバグを回避するには、を呼び出すコードを挿入postMessage()する必要があります。

次のスクリプトはその方​​法を示しています。これ:

  • iframe とそれを含むページの両方で実行されます。
  • クロス ドメイン iframe を処理します。
  • 次のロジックを持つスクリプト間制御を示します。
    1. コンテナー ページは、iframe からのメッセージをリッスンするように設定します。
    2. iframe は、コンテナー ページからのメッセージをリッスンするように設定します。
    3. iframe は、最初のメッセージをコンテナー ページに送信します。
    4. コンテナー ページがそのメッセージを受信すると、別のメッセージを iframe に送り返します。

このスクリプトをインストールします (何年にもわたってターゲット サイトが変更されたため、CertainPerformance のおかげで更新されました)。

// ==UserScript==
// @name        _Cross iframe, cross-domain, interscript communication
// @include     http://fiddle.jshell.net/2nmfk5qs/*
// @include     http://puppylinux.com/
// @grant       none
// ==/UserScript==
/* eslint-disable no-multi-spaces */

if (window.top === window.self) return;
console.log ("Script start...");
if (window.location.href.includes('fiddle')) {
    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://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://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  = 'parent.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");


次に、jsFiddle のこのテスト ページにアクセスします。

これは、javascript コンソールに表示されます。

スクリプト開始...
Userscript は MAIN ページにあります。
iframe からのメッセージ 1 を待機しています...
スクリプト終了
スクリプト開始...
Userscript は FRAMED ページにあります。
含まれているページからのメッセージ 2 を待機しています...
スクリプト終了
コンテナー ページは、メッセージ「***Message 1, from iframe***」を受け取りました。
iframe はメッセージ「***Message 2, from the container page***」を受け取りました。
于 2012-08-02T09:00:45.733 に答える