如何使用 JSF 打开弹出窗口而不被浏览器阻止
How to open a pop-up using JSF without it being blocked by the browser
我正在开发 PrimeFaces 6.0、JSF 2.2 (Mojarra 2.2.7) 应用程序。
我需要从外部站点加载网页并突出显示 DOM 节点。我的做法是创建一个JavaScript函数来打开一个弹出窗口window,通过servlet加载网页(避免跨域问题)并突出显示该节点。我发送到函数的参数是在托管 bean 中生成的。
我尝试了两种不同的方式:
- 在我的操作中使用
RequestContext.getCurrentInstance().execute("myFunction(...)")
(是的,我正在使用 PrimeFaces)。
- 在我的命令按钮上使用
oncomplete="#{myBean.myJsCall}"
。
两种方式调用都已执行且调用正确,但我 运行 进入浏览器 (Chromium) 的弹出窗口拦截器:
有没有办法在 JSF 或 PrimeFaces 中打开弹出窗口而不被阻止?
这不是真正相关的,但这是我的 JavaScript 函数的简化版本。
我使用纯 HTML 和 JS 开发了这个脚本。它在那里打开弹出窗口而没有拦截器干扰。此外,在 运行 运行 JSF 应用程序时将调用粘贴到控制台时,会打开弹出窗口。
function myFunction(url, selector) {
var popup = window.open("", "popup", "height=500,width=700");
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.onreadystatechange = function() {
if (req.readyState === XMLHttpRequest.DONE) {
popup.document.open();
popup.document.write(req.responseText);
popup.document.close();
popup.document.addEventListener(
"DOMContentLoaded",
function() { /* Some code highlighting the selector */ },
false
);
}
}
req.send();
}
当您尝试在 JavaScript 中打开一个新的 window 时,这不是由用户操作(如点击)直接触发的,而是在例如执行 JSF 后触发的回调 ajax请求,被浏览器拦截。
此行为在以下问题中有所描述:jquery window.open in ajax success being blocked。
作为解决方法,您可以在 JSF ajax 请求之前打开一个 window。在使用 JSF HTML 标签的命令按钮的情况下,这可以通过使用来完成:
<h:commandButton ... onclick="prepareWindow()"/>
onclick
将按原样呈现。但是,当您使用 PrimeFaces 时,您 不能 使用:
<p:commandButton ... onclick="prepareWindow()"/>
PrimeFaces 包装 onclick
导致间接执行,因此弹出窗口被阻止。
无论如何,通过一些额外的技巧,您可以使用某种看起来像 PrimeFaces 按钮的按钮来实现此功能。但是黑客的数量越来越多了。
我选择使用 p:dialog
和 iframe
。首先,如果您使用 p:layout
,不要 将对话框放置在任何布局单元中。
对话框:
<p:dialog header="Preview"
widgetVar="previewDlg" modal="true" width="1000" height="600"
dynamic="true">
<iframe src="about:blank"
class="previewIframe"
style="position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;border:0"></iframe>
</p:dialog>
按钮:
<p:commandButton value="Show"
...
onclick="PF('previewDlg').show()"
action="#{myBean.showPreview('previewIframe')}"/>
动作:
public void showPreview(String iframeClass) {
...
RequestContext.getCurrentInstance().execute(js);
}
JavaScript函数:
function myFunction(iframeClass, url, selector) {
var iframe = $("iframe[class=" + iframeClass + "]")[0];
iframe.contentDocument.location = "about:blank";
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.onreadystatechange = function() {
if (req.readyState === XMLHttpRequest.DONE) {
iframe.contentDocument.open();
iframe.contentDocument.write(req.responseText);
iframe.contentDocument.close();
iframe.contentDocument.addEventListener(
"DOMContentLoaded",
function() { /* Some code highlighting the selector */ },
false
);
}
}
req.send();
}
有一个简单的出路。在 ajax 数据提交后,打开一个空的弹出式 onclick(直接由用户诱导,因此不会被阻止)并重定向 window 到更新的模型:
<p:commandButton value="open popup" process="@form"
onclick="myNamespace.openPreview()"
oncomplete="myNamespace.relocatePreview()"/>
你的 js 应该是这样的:
myNamespace.openPreview = function () {
myNamespace.prev = window.open('', '_blank');
}
myNamespace.relocatePreview = function () {
myNamespace.prev.location = 'preview.xhtml?faces-redirect=true';
}
我正在开发 PrimeFaces 6.0、JSF 2.2 (Mojarra 2.2.7) 应用程序。
我需要从外部站点加载网页并突出显示 DOM 节点。我的做法是创建一个JavaScript函数来打开一个弹出窗口window,通过servlet加载网页(避免跨域问题)并突出显示该节点。我发送到函数的参数是在托管 bean 中生成的。
我尝试了两种不同的方式:
- 在我的操作中使用
RequestContext.getCurrentInstance().execute("myFunction(...)")
(是的,我正在使用 PrimeFaces)。 - 在我的命令按钮上使用
oncomplete="#{myBean.myJsCall}"
。
两种方式调用都已执行且调用正确,但我 运行 进入浏览器 (Chromium) 的弹出窗口拦截器:
有没有办法在 JSF 或 PrimeFaces 中打开弹出窗口而不被阻止?
这不是真正相关的,但这是我的 JavaScript 函数的简化版本。
我使用纯 HTML 和 JS 开发了这个脚本。它在那里打开弹出窗口而没有拦截器干扰。此外,在 运行 运行 JSF 应用程序时将调用粘贴到控制台时,会打开弹出窗口。
function myFunction(url, selector) {
var popup = window.open("", "popup", "height=500,width=700");
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.onreadystatechange = function() {
if (req.readyState === XMLHttpRequest.DONE) {
popup.document.open();
popup.document.write(req.responseText);
popup.document.close();
popup.document.addEventListener(
"DOMContentLoaded",
function() { /* Some code highlighting the selector */ },
false
);
}
}
req.send();
}
当您尝试在 JavaScript 中打开一个新的 window 时,这不是由用户操作(如点击)直接触发的,而是在例如执行 JSF 后触发的回调 ajax请求,被浏览器拦截。
此行为在以下问题中有所描述:jquery window.open in ajax success being blocked。
作为解决方法,您可以在 JSF ajax 请求之前打开一个 window。在使用 JSF HTML 标签的命令按钮的情况下,这可以通过使用来完成:
<h:commandButton ... onclick="prepareWindow()"/>
onclick
将按原样呈现。但是,当您使用 PrimeFaces 时,您 不能 使用:
<p:commandButton ... onclick="prepareWindow()"/>
PrimeFaces 包装 onclick
导致间接执行,因此弹出窗口被阻止。
无论如何,通过一些额外的技巧,您可以使用某种看起来像 PrimeFaces 按钮的按钮来实现此功能。但是黑客的数量越来越多了。
我选择使用 p:dialog
和 iframe
。首先,如果您使用 p:layout
,不要 将对话框放置在任何布局单元中。
对话框:
<p:dialog header="Preview"
widgetVar="previewDlg" modal="true" width="1000" height="600"
dynamic="true">
<iframe src="about:blank"
class="previewIframe"
style="position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;border:0"></iframe>
</p:dialog>
按钮:
<p:commandButton value="Show"
...
onclick="PF('previewDlg').show()"
action="#{myBean.showPreview('previewIframe')}"/>
动作:
public void showPreview(String iframeClass) {
...
RequestContext.getCurrentInstance().execute(js);
}
JavaScript函数:
function myFunction(iframeClass, url, selector) {
var iframe = $("iframe[class=" + iframeClass + "]")[0];
iframe.contentDocument.location = "about:blank";
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.onreadystatechange = function() {
if (req.readyState === XMLHttpRequest.DONE) {
iframe.contentDocument.open();
iframe.contentDocument.write(req.responseText);
iframe.contentDocument.close();
iframe.contentDocument.addEventListener(
"DOMContentLoaded",
function() { /* Some code highlighting the selector */ },
false
);
}
}
req.send();
}
有一个简单的出路。在 ajax 数据提交后,打开一个空的弹出式 onclick(直接由用户诱导,因此不会被阻止)并重定向 window 到更新的模型:
<p:commandButton value="open popup" process="@form"
onclick="myNamespace.openPreview()"
oncomplete="myNamespace.relocatePreview()"/>
你的 js 应该是这样的:
myNamespace.openPreview = function () {
myNamespace.prev = window.open('', '_blank');
}
myNamespace.relocatePreview = function () {
myNamespace.prev.location = 'preview.xhtml?faces-redirect=true';
}