[英]JavaScript window.open returns null sometimes
我正在嘗試維護一個我沒有編寫的系統(我們不是所有人嗎?)。 它是用 C Sharp 和 JavaScript 編寫的,有 Telerik 報告。
它在 JavaScript 中包含以下代碼,當用戶單擊按鈕以在單獨的窗口中顯示報告時運行:
var oIframe = $("iframe id='idReportFrame' style='display:none' name='idReportFrame' src=''>");
oIframe.load(function() { parent.ViewReports(); });
oIframe.appendTo('body');
try
{
$('#idReportForm').attr('target', 'idReportFrame');
$('#idReportForm').submit();
}
catch (err) { // I did NOT write this
}
然后加載函數:
function ViewReports()
{
var rptName = $("#ReportNameField").val();
if (rptName == '') { return false; }
var winOption = "fullscreen=no,height=" + $(window).height() + "left=0,directories=yes,titlebar=yes,toolbar=yes,location=yes,status=no,menubar=yes,scrollbars=no,resizable=no, top=0, width=" + $(window).width();
var win = window.open('@Url.Action("ReportView", "MyController")?pReportName=' + rptNameCode, 'Report', winOption);
win.focus();
return false;
}
當我執行此操作時(至少在 Chrome 中),它會彈出窗口並將報告放入其中。 但是,c# 代碼中的斷點表明它被調用了 2 或 3 次。 JavaScript 中的斷點和 Chrome 中 JavaScript 調試環境中的小日志的檢查表明,對win.focus()
的調用在成功之前失敗了一兩次。 它返回一個未定義的值,然后似乎再次執行了上面的第一個例程。
我傾向於認為這是某種時間問題,除了 window.open() 調用應該是同步的,我不知道為什么它有時會成功而不是其他人。 有一個例程在窗口加載時執行,也許這在某種程度上搞砸了從 open() 返回的值。
我不是一個 JavaScript 人,正如你們中的那些人現在可能已經知道的那樣。 如果我放在這里的代碼有什么地方你可以告訴我是不正確的,那就太好了; 我更希望有人能夠解釋框架內彈出式報告應該如何工作。 希望我可以做到這一點,而不必替換我擁有的太多代碼,因為它很脆弱,我們應該說,在編寫時並沒有考慮到重構。
據我所知,window.open 在打開失敗時將返回 null。 某些原因可能會阻止瀏覽器多次打開其他窗口; 也許它是一個彈出窗口阻止程序。
url 的實際加載和窗口的創建是異步完成的。
https://developer.mozilla.org/en-US/docs/Web/API/Window.open
彈出窗口阻止
過去,邪惡網站經常濫用彈出窗口。 一個糟糕的頁面可能會打開大量帶有廣告的彈出窗口。 所以現在大多數瀏覽器都試圖阻止彈出窗口並保護用戶。
如果在用戶觸發的事件處理程序(如 onclick)之外調用,大多數瀏覽器會阻止彈出窗口。
例如:
// popup blocked window.open('https://javascript.info'); // popup allowed button.onclick = () => { window.open('https://javascript.info'); };
我剛剛遇到了這個問題,這似乎是因為我在調用window.open
的行上有一個斷點,並且正在 Chrome 開發工具中逐步執行代碼。 這是非常偶然的,並且似乎失敗(返回空值,不打開窗口,無論是否已經存在)多次成功。
我讀了@Joshua 的評論,說創建是異步完成的,所以我認為每次我一步都強制代碼“停止”可能會以某種方式把事情搞砸(盡管在像var w = window.open(...)
這似乎不可能發生)。
所以,我拿出了我的斷點......一切都開始完美運行!
我還注意到https://developer.mozilla.org/en-US/docs/Web/API/Window/open ,他們指定如果您重新使用窗口變量和名稱( window.open
的第二個window.open
)然后推薦某種代碼模式。 在我的情況下,我想向它寫入 HTML 內容,而不是給它一個 URL 並讓它通過網絡異步加載內容,並且我可能會重復調用整個函數而不考慮用戶關閉彈出的窗口. 所以現在我有這樣的事情:
var win; // initialises to undefined
function openWindow() {
var head = '<html><head>...blahblah..</head>';
var content = '<h1>Amazing content<h1><p>Isn\'t it, though?</p>';
var footer = '</body></html>';
if (!win || win.closed) {
// window either never opened, or was open and has been closed.
win = window.open('about:blank', 'MyWindowName', 'width=100,height=100');
win.document.write(head + content + footer);
} else {
// window still exists from last time and has not been closed.
win.document.body.innerHTML = content;
}
}
我不相信應該給write
調用提供完整的<html>
標頭,但這對我來說似乎 100% 有效。
[編輯] 我發現 Stackoverflow 上的代碼片段具有某種防止window.open
的安全功能,但此 jsfiddle 顯示了上面的代碼工作,並進行了調整以顯示遞增計數器以證明內容更新按預期工作. https://jsfiddle.net/neekfenwick/h8em5kn6/3/
有點晚了,但我認為這是由於窗口實際上沒有在 js 中關閉,或者可能是內存指針沒有被取消引用。 我遇到了同樣的問題,我通過將調用包含在 try finally 塊中來解決它。
try {
if (!winRef || winRef.closed) {
winRef = window.open('', '', 'left=0,top=0,width=300,height=400,toolbar=0,scrollbars=0,status=0,dir=ltr');
} else {
winRef.focus();
}
winRef.document.open();
winRef.document.write(`
<html>
<head>
<link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.min.css">
</head>
<body>
${$(id).remove('.print-exclude').html()}
</body>
</html>
`);
winRef.document.close();
winRef.focus();
winRef.print();
} catch { }
finally {
if (winRef && !winRef.closed) winRef.close();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.