4

我有一个网络应用程序。它在 Google Chrome 中运行,不需要在任何其他浏览器中运行。

我有在服务器上生成并在 AJAX 请求中发送回客户端的 PDF 数据。我从 PDF 数据创建了一个 blob。我使用 window.URL.createObjectURL 从 blob 创建一个 URL,然后将其加载到以前创建的用于显示 PDF 的窗口(我的 preview_window)中。

为了加载 URL,我设置了 preview_window.location.href。

我想调用 revokeObjectURL 以避免在窗口中生成和预览新 PDF 时浪费越来越多的资源。问题是在设置 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 事件。您必须在第二页中注入一些脚本来调用其window.opener函数。

但是由于您打开的是 pdf 文件,浏览器将重新解析整个页面,并且您注入的代码将消失。

正如您在评论中发现的那样,解决方案是将 blob 的 url 注入 iframe 中,然后等待此 iframe 的加载事件。

方法如下:

索引.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 回答