9

私は2つのウィンドウを持っており、1つは別のウィンドウから開いているので、opener「子」ウィ​​ンドウにプロパティがあります。

親ウィンドウにはグローバルスコープの関数があり、最初の引数として関数を使用して呼び出す必要があります(コールバックとして使用されます)。

両方のページが同じドメインから開かれているので、同一生成元ポリシーの制限はありません(そう願っています)...

子ウィンドウに次のようなコードがあります

if(window.opener) {
    window.opener.myFunction(function() { ... });
}

IEで実行しようとするまで、すべて正常に動作します。このブラウザでは、によって受け取られる引数myFunctionは常にタイプですObject(でチェックされますtypeof)。のコードmyFunctionは次のようなものです。

window.myFunction = function(cb) {
    alert('Callback type is ' + (typeof cb));
    if(typeof cb == 'function') 
        cb();
    else
        alert('Not a function!');
}

ライブデモ:http ://elifantiev.ru/ie-opener-issue/first.html

質問は次のとおりです。

  1. これは標準に準拠した動作ですか?
  2. この問題の回避策はありますか?
4

4 に答える 4

6

typeof は「オブジェクト」を返しますが、関数は期待どおりに機能します。呼び出すcb()と関数が実行されます。

パラメーターが関数であるかどうかを判断するために使用する代わりにtypeof、すべての関数が持っていると予想される call プロパティをテストします。

if (cb && cb.call) { cb(); }

関数を期待するものに渡す場合は、次のようにラップできます。

function newCb() {
    return cb.apply(object, arguments);
}

また、関数を親から子に渡す場合、typeof もオブジェクトであることに注意してください。元の関数をオブジェクトとしての関数と比較すると (ラウンド トリップ後)、true が返されます。これは、何らかの理由で元の関数への参照が必要な場合 (たとえば、サブスクライブを解除する場合) に重要です。

于 2012-05-09T21:42:28.523 に答える
2

これは仕様によるもののようです。

これについての記事があります

https://bugzilla.mozilla.org/show_bug.cgi?id=475038

各ウィンドウは異なるプロトタイプチェーンを持つことができるため、関数を期待どおりに渡すことはできません。確認するには、次のようなことを試してください。

   var popup = window.open('second.html');

   window.myFunction = function(cb) {
            alert(cb instanceof Function);       //false
            alert(cb instanceof popup.Function); //true
   }

したがって、親側で心配する関数が多数ある場合に、適切な関数検証を行う方法は次のとおりです(プロトタイプは嫌いですが、今回は行き詰まっていると思います)。

親ウィンドウ:

<html>
<script type="text/javascript">
    /* give all our functions the validation check at once */
    Function.prototype.remote = function(cb) {
        if(cb instanceof popup.Function) {
            this(cb);
        } else {
            alert('Not a function!');
        }
    };

    var popup,
    myFunction = function(cb) {
        cb();
    },
    test = function(cb) {
        cb();
    }

</script>   
<body>
    <a href="#" onclick="popup = window.open('second.html'); return false;">Open window</a>
</body>
</html>

子ウィンドウ:

<html>
<body>
    <script type="text/javascript">
        var Parent = window.opener;
        if(Parent) {
            Parent.myFunction.remote(function(){
                alert('callback!');
            });

            Parent.test.remote(function() {
               alert('callback again');
            });
        }
    </script>
    This is a second page!
</body>
</html>

そして、これが実際の例です:http: //dl.dropbox.com/u/169857/first.html

于 2012-05-15T04:03:57.130 に答える
2

今のところこれを機能させることができたとしても、2 つのブラウザー ウィンドウが相互に関数を直接呼び出す機能がずっと長く続くとは思えません。シナリオからクロスドメインの問題を取り除いたとしても、セキュリティ上の懸念が多すぎます。

これを実現し、すべてのブラウザで機能することを保証するための唯一の将来性のある方法は、IE8 以降を含む最新のすべてのブラウザでサポートされているクロスドキュメント メッセージング APIを使用することです。

この問題を解決する必要があるときに見つけた最も詳細な例は、MDN の window.postMessage の記事です。

要するに、一方からメッセージを投稿するための呼び出しです。たとえば、次のようになります。

otherWindow.postMessage(message, targetOrigin);

そして、反対側のイベント ハンドラー:

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event)
{
  alert("I got it!\n" + event.data);
}

IE6 と IE7 では、ウィンドウが同じドメインからのものである場合、今のところこれらのクロスウィンドウ呼び出しを行うことができるかもしれませんが、IE8 以降では、この API を使用することを期待する可能性が高く、他のブラウザーは最終的に完全に元に戻ると思います。このはるかに安全な通信メカニズム。

状況を考慮して、共有ライブラリを使用してコードを共有することを強くお勧めします (LAB.js や require.js のようなものを使用するか、Jquery の getScript() 関数だけを使用することもできます)。今日使用しようとしているコールバック関数の代わりに、イベント。

アップデート


古いブラウザーに postMessage サポートを追加するために使用できるポリフィルがあります。クロスドメイン呼び出しを行っていないので、Ben Alman のJquery postMessage plugin から始めます。私はそれを使用したことはありませんが、Ben の優れた Jquery BBQ プラグインを使用しました。サポートされている場合は組み込みメソッドにフォールバックし、古いブラウザーの代替メソッドでのみ shim する必要があります。IE7で動作すると主張しています...

Ben のプラグインで問題が解決しない場合は、easyXDM を試すこともできますが、セットアップが少し複雑に見えます。

于 2012-05-17T18:23:11.957 に答える
-1

子ウィンドウを開いた後、親によって作成された関数をそのwindowコンテキストに登録できます。jsFiddleで実行されている次のコードを確認できます。

<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>

// will be called by the child window
function MyExportedCallback(x) {
    $("#my-callback-result").text("this callback was run with '" + x + "'.");
}

// will open a child window and create content for testing
function MyLinkHandler() {
    var wnd = window.open("about:blank");

    // IMPORTANT: this is where the parent defined function is "registered"
    // into child window scope
    wnd["myExternal"] = MyExportedCallback;

    // auxiliary code to generate some HTML to test the external function
    var put = function(x) { wnd.document.write(x); };
    put("<html><body>");
    put("<a href='#' onclick='window.myExternal(123);'>");
    put("click me to run external function");
    put("</a>");
    put("</body></html>");
}

// attach events
$.ready(function() {
    $("#my-link").click(MyLinkHandler);
});

</script>
<body>
<p><a id="my-link" href="#">Open window</a></p>
<p id="my-callback-result">waitting callback...</p>
</body>
</html>
于 2012-05-17T15:30:05.777 に答える