我正在尝试维护一个我没有编写的系统(我们不都是这样吗?)。它是用 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/zh-CN/docs/Web/API/Window.open
弹出窗口拦截
过去,恶意网站大量滥用弹窗。一个坏的页面可能会打开 大量带有广告的弹出窗口。所以现在大多数浏览器都试图阻止 弹出窗口并保护用户。
大多数浏览器会阻止在外部调用的弹出窗口 用户触发的事件处理程序,如 onclick。
例如:
// popup blocked window.open('https://javascript.info'); // popup allowed button.onclick = () => { window.open('https://javascript.info'); };
我刚刚遇到这个,这似乎是因为我在 Chrome 开发工具中调用
window.open
的行上有一个断点并且正在单步执行代码。这是非常偶然的,似乎失败了(返回 null,不打开窗口,无论是否已经存在)成功的次数更多。
我读到@Joshua 的评论说创建是异步完成的,所以我认为每次我执行步骤时强制代码“停止”可能会以某种方式搞砸(尽管像
var w = window.open(...)
这样的单行看起来不是这样的可能发生)。
所以,我去掉了我的断点..一切都开始完美地工作了!
我还注意到 https://developer.mozilla.org/en-US/docs/Web/API/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();
}
您必须指定新窗口的宽度和高度。 所以
window.open("https://avangsoft.ir/", "MyWindowName","width=100,height=100");
有效但
window.open("https://avangsoft.ir/", "MyWindowName");
不工作