PrimeFaces 页面 "hangs" 更新包含 JS 的元素 "document.write"

PrimeFaces page "hangs" on update of element containing JS "document.write"

为什么 PrimeFaces 命令按钮无法更新包含 JavaScript <script>document.write("some text")</script> 元素的元素?浏览器 "hangs" 更新此类元素。

例如:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:p="http://primefaces.org/ui">

    <h:head>
        <title>my page</title>
    </h:head>

    <h:body>
        <h:form>
            <p:commandButton
                id="pushMeButton"
                value="push me"
                update="testPanel"
                action="#{myManagedBean.doNothing()}">
            </p:commandButton>
        </h:form>

        <p:panel id="testPanel">
            <script>
                document.write("test text 1");
            </script>
            <script>
                document.write("test text 2");
            </script>

           <h:outputText value="#{myManagedBean.getSomeText()}" />
        </p:panel>
    </h:body>
</html>

按下 "pushMeButton" 后,浏览器仅显示带有文本 "test text 1" 和 "hangs" 的空页面(firefox 选项卡中的图标显示页面仍在无限期加载,但没有活动请求在 firebug).

按下按钮后浏览器收到的部分响应看起来是正确的:

<partial-response id="j_id1">
    <changes>
        <update id="testPanel">
            <![CDATA[
            <div id="testPanel" class="ui-panel ui-widget ui-widget-content ui-corner-all" data-widget="widget_testPanel">
                <div id="testPanel_content" class="ui-panel-content ui-widget-content">
                    <script>
                        document.write("test text 1");
                    </script>
                    <script>
                        document.write("test text 2");
                    </script>
                    some text from managed bean method getSomeText()
                </div>
            </div>
            <script id="testPanel_s" type="text/javascript">
                PrimeFaces.cw("Panel","widget_testPanel",{id:"testPanel",widgetVar:"widget_testPanel"});
            </script>
            ]]>
        </update>
        <update id="j_id1:javax.faces.ViewState:0"><![CDATA[1747871418605077113:5684199653317714547]]></update>
    </changes>
</partial-response>

我正在使用 PrimeFaces:5.2.5 和 Mojarra:2.2.8

我可以在 Firefox v44.0.2 和 IE v11 上重现行为,但在 Chrome v48 上一切正常(显示相同的页面,没有任何变化)。

上面的 xhtml sniped 只是我正在解决的问题的简化版本。我使用 "document.write" 是因为我的 Web 应用程序 "imports" 一些来自遗留系统的 HTML 部分无法更改(我从 Liferay 门户导入菜单)。 如果我将 "document.write" 更改为其他内容,例如 document.getElementById('someExistingElementId').innerHTML = 'New text'; 一切正常。

看来BalusC "I think I see the root cause. IE6/7/8 unfortunately doesn't run the embedded scripts when document.write() is been used to replace the DOM" (http://forum.primefaces.org/viewtopic.php?f=3&t=18937&start=20) 的评论与我的问题有关,但我不明白为什么它不起作用以及是否有可能使其在现代浏览器上运行。

问题与 PrimeFaces 或 JSF 没有直接关系 - 它是 javascript 工作原理。

"If it is used after an HTML document is fully loaded, it will delete all existing HTML." (http://www.w3schools.com/jsref/met_doc_write.asp)

我可以使用 HTML 和 JS 重现类似情况:

<!DOCTYPE html>
<html>
    <body>    
        <p>Click the button to trigger a function</p>    
        <button onclick="myFunction()">Click me</button>
        <script>
            function myFunction() {
                document.write("test text 1");
            }
        </script>    
   </body>
</html>

部分更新更新已加载的文档 - 这就是为什么单击按钮后仅显示 "test text 1" 的原因。因为在第一个 <script>document.write("test text 1");<script> 执行后所有文档都被覆盖。

Firefox "hangs" 因为 "document.close" 没有被调用(如果文件输出流没有打开 "document.write" 会打开它,所以需要关闭它)。

所以简历​​是:如果页面的那部分可以用 ajax 调用更新,则不可能在 JSF 页面中使用 document.write(...);

在大多数情况下,应避免在 JSF 页面中使用 document.write(...),因为并不总是能够控制更新页面的哪一部分。例如OmniFace FullAjaxExceptionHandler会在异常后执行update="@all",所以错误页面不能有任何document.write(...)语句。