4

私はウェブアプリケーションを持っています。Google Chrome で実行され、他のブラウザーで動作する必要はありません。

サーバーで生成され、AJAX 要求でクライアントに送り返された PDF データがあります。PDF データからブロブを作成します。window.URL.createObjectURL を使用して blob から URL を作成し、それを PDF を表示するために以前に作成したウィンドウ (私の preview_window) に読み込みます。

URL を読み込むために、preview_window.location.href を設定します。

新しい PDF が生成されてウィンドウでプレビューされるたびにリソースが無駄になるのを避けるために、revokeObjectURL を呼び出したいと思います。問題は、preview_window.location.href を設定した直後に呼び出すのが早すぎて、PDF が表示されなくなることです。そのため、URL が読み込まれた後にのみ revokeObjectURL を呼び出したいと思います。この目的で preview_window.onload をコールバックに設定しようとしましたが、呼び出されません。

私が知りたいのですが:

  1. 私がやろうとしているように、ウィンドウが URL をロードしたときにコールバックをトリガーすることは可能ですか? どのように?
  2. revokeObjectURL がタイムリーに呼び出されるようにする別の方法はありますか?

ウィンドウが URL の読み込みを完了したときに revokeObjectURL をトリガーできない場合は、新しい URL を生成する直前に各 URL を取り消すことができます。しかし、可能であれば、読み込みが完了したらすぐに URL を取り消したいと思います。

状況をよく示す html ファイルを用意しました。

<html>
    <head>
        <title>Show PDF Demo</title>
        <script>
            var build_blob = function(mime_type, data) {
                var buf = new ArrayBuffer(data.length);
                var ia = new Uint8Array(buf);
                for (var i = 0; i < data.length; i++) ia[i] = data.charCodeAt(i);
                var blob = new Blob([ buf ], { type: mime_type });
                return blob;
            };

            window.onload = function(e) {
                document.getElementById('preview_button').onclick = function(e) {

                    // open the window in the onclick handler so we don't trigger popup blocking
                    var preview_window = window.open(null, 'preview_window');

                    // use setTimeout to simulate an asynchronous AJAX request
                    setTimeout(function(e) {
                        var pdf_data = atob(
                            "JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZwovT3V0bGluZXMgMiAwIFIKL1BhZ2Vz" +
                            "IDMgMCBSCj4+CmVuZG9iagoyIDAgb2JqCjw8IC9UeXBlIC9PdXRsaW5lcwovQ291bnQgMAo+Pgpl" +
                            "bmRvYmoKMyAwIG9iago8PCAvVHlwZSAvUGFnZXMKL0tpZHMgWzQgMCBSXQovQ291bnQgMQo+Pgpl" +
                            "bmRvYmoKNCAwIG9iago8PCAvVHlwZSAvUGFnZQovUGFyZW50IDMgMCBSCi9NZWRpYUJveCBbMCAw" +
                            "IDUwMCAyMDBdCi9Db250ZW50cyA1IDAgUgovUmVzb3VyY2VzIDw8IC9Qcm9jU2V0IDYgMCBSCi9G" +
                            "b250IDw8IC9GMSA3IDAgUiA+Pgo+Pgo+PgplbmRvYmoKNSAwIG9iago8PCAvTGVuZ3RoIDczID4+" +
                            "CnN0cmVhbQpCVAovRjEgMjQgVGYKMTAwIDEwMCBUZAooU01BTEwgVEVTVCBQREYgRklMRSkgVGoK" +
                            "RVQKZW5kc3RyZWFtCmVuZG9iago2IDAgb2JqClsvUERGIC9UZXh0XQplbmRvYmoKNyAwIG9iago8" +
                            "PCAvVHlwZSAvRm9udAovU3VidHlwZSAvVHlwZTEKL05hbWUgL0YxCi9CYXNlRm9udCAvSGVsdmV0" +
                            "aWNhCi9FbmNvZGluZyAvTWFjUm9tYW5FbmNvZGluZwo+PgplbmRvYmoKeHJlZgowIDgKMDAwMDAw" +
                            "MDAwMCA2NTUzNSBmCjAwMDAwMDAwMDkgMDAwMDAgbgowMDAwMDAwMDc0IDAwMDAwIG4KMDAwMDAw" +
                            "MDEyMCAwMDAwMCBuCjAwMDAwMDAxNzkgMDAwMDAgbgowMDAwMDAwMzY0IDAwMDAwIG4KMDAwMDAw" +
                            "MDQ2NiAwMDAwMCBuCjAwMDAwMDA0OTYgMDAwMDAgbgp0cmFpbGVyCjw8IC9TaXplIDgKL1Jvb3Qg" +
                            "MSAwIFIKPj4Kc3RhcnR4cmVmCjYyNQolJUVPRg=="
                        );

                        /*
                            Warning: for my Chrome (Version 44.0.2403.155 m), the in-built PDF viewer doesn't seem 
                            to work with a blob when this html page is loaded from the local filesystem.  I have only 
                            got this to work when fetching this page via HTTP.
                        */

                        var pdf_blob = build_blob('application/pdf', pdf_data);

                        var pdf_url = window.URL.createObjectURL(pdf_blob);

                        preview_window.onload = function(e) {
                            console.log("preview_window.onload called");  // never happens
                            window.URL.revokeObjectURL(pdf_url);
                        };

                        preview_window.location.href = pdf_url;
                        console.log("preview_window.location.href set");

                    }, 500);
                };
            };
        </script>
    </head>
    <body>
        <button id="preview_button">Show Preview</button>
    </body>
</html>

上記のデモ コードではそれを回避していますが、アプリケーション用に jQuery をロードしています。

検索でこの質問を見つけましたが、その状況ではメインウィンドウ(「ウィンドウ」)が新しいURLを指しており、ウィンドウがウィンドウから来た場合に違いがあるかどうかをコメントで尋ねると、OPは応答を受け取りませんでした。開いた。

4

1 に答える 1

0

open()お気づきのように、オープナーから ed windows の onload イベントを設定することはできません。関数を呼び出す 2 番目のページにスクリプトを挿入する必要がありwindow.openerます。

しかし、pdf ファイルを開いているため、ブラウザーはページ全体を再解析し、挿入されたコードは消えてしまいます。

コメントでわかったように、解決策は、blob の URL を iframe に挿入し、この iframe の load イベントを待つことです。

方法は次のとおりです。

index.html

    <script>
        // The callback that our pop-up will call when loaded
        function imDone(url){
            window.URL.revokeObjectURL(url);
            }

        var build_blob = function(mime_type, data) {
            var buf = new ArrayBuffer(data.length);
            var ia = new Uint8Array(buf);
            for (var i = 0; i < data.length; i++) ia[i] = data.charCodeAt(i);
            var blob = new Blob([ buf ], { type: mime_type });
            return blob;
        };
        var preview_window=null;
        window.onload = function(e) {
            document.getElementById('preview_button').onclick = function(e) {
              if(preview_window===null || preview_window.closed){
                // open the window in the onclick handler so we don't trigger popup blocking
                preview_window = window.open('html2.html', 'preview_window');
              }
               // avoid reopening the window since it may cache our last blob
              else preview_window.focus();

                // use setTimeout to simulate an asynchronous AJAX request
                setTimeout(function(e) {
                    var pdf_data = /* Your pdf data */

                    var pdf_blob = build_blob('application/pdf', pdf_data);

                    var pdf_url = window.URL.createObjectURL(pdf_blob);
                    // Simple loop if our target document is not ready yet
                    var loopLoad = function(url){
                      var doc = preview_window.document;
                      if(doc){
                        var iframe = doc.querySelector('iframe');
                        if(iframe)iframe.src = url;
                        else setTimeout(function(){loopLoad(url);},200);
                      }
                      else setTimeout(function(){loopLoad(url);},200)
                    };
                    loopLoad(pdf_url);

                }, 0);
            };
        };
    </script>

html2.html

<html>
    <head>
        <title>Iframe PDF Demo</title>
        <style>
            body, html, iframe{margin:0; border:0}
        </style>
    </head>
    <body>
    <iframe width="100%" height="100%"></iframe>
    <script>
        document.querySelector('iframe').onload = function(){
            //first check that our src is set
            if(this.src.indexOf('blob')===0)
                // then call index.html's callback
                window.opener.imDone(this.src);
            }
    </script>
    </body>
</html>

ライブデモ

于 2015-08-26T01:23:17.483 に答える