首页 > 解决方案 > 使用 window.open 检测“php://output”的完成

问题描述

我使用PhpSpreadsheet以这种方式导出 mysql 数据:

第 1 页:

button触发window.open到带有导出脚本的页面

window.open('/export.php?data.., '_self');

第 2 页(export.php):

整个系统的出口和php://output

ob_end_clean();
ob_start();
$objWriter->save('php://output');            
exit;

我可以以某种方式了解导出页面是否已完成?我需要这个来触发覆盖。

我试过什么?

查看stackoverflow我尝试了这个解决方案,但没有奏效:

overlay.style.display = "block";
let myPopup =  window.open('/export.php?data.., '_self');
myPopup.addEventListener('load', () => {
   console.log('load'); //just for debug
   overlay.style.display = "none";
}, false);

标签: javascriptphp

解决方案


这将执行一个 ajax 请求,这将导致下载而不用 jQuery 刷新页面

<button id='download'>Download Spreadsheet</button>
<form method='get' action='/export.php?' id='hiddenForm'>
  <input type='hidden' name='foo' value='bar' />
  <input type='hidden' name='foo2' value='bar2' />
</form>


$(document).on('click', '#download', function (e) {
    e.preventDefault();
    $('#hiddenForm').submit();
});

确保您的 PHP 输出正确的内容类型

if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    readfile($file);
    exit;
}

另外一个选项

根据这篇文章,没有可用于真正检测跨所有不同浏览器加载 javascript 窗口对象的 api。此方法使用延迟回调和postMessage方法来适应大多数现代浏览器。

function defer (callback) {
    var channel = new MessageChannel();
    channel.port1.onmessage = function (e) {
        callback();
    };
    channel.port2.postMessage(null);
}

var awaitLoad = function (win, cb){
    var wasCalled = false;
    function unloadListener(){
        if (wasCalled)
            return;
        wasCalled = true;
        win.removeEventListener("unload", unloadListener);
        win.removeEventListener("pagehide", unloadListener);
        // Firefox keeps window event listeners for multiple page loads
        defer(function (){
            win.document.readyState;
            // IE sometimes throws security error if not accessed 2 times
            if (win.document.readyState === "loading")
                win.addEventListener("load", function loadListener(){
                    win.removeEventListener("load", loadListener);
                    cb();
                });
            else
                cb();
        });
    };
    win.addEventListener("unload", unloadListener);
    win.addEventListener("pagehide", unloadListener);
    // Safari does not support unload
}


w = window.open();
w.location.href="/export.php?data=foo";
awaitLoad(w, function (){
   console.log('got it')
});

推荐阅读