webview - JavaFX WebView 在重新加载时重新创建窗口

标签 webview javafx reload onload javafx-webengine

我正在创建一个页面,该页面将在 Java 的 WebView 中打开,或在外部浏览器中手动打开。如果页面是从 Java 加载的——我需要它来执行特定的回调,因为 Java 被用作一种后端,但如果页面是手动加载的,它应该从其资源加载不同的数据。所以我正在尝试注册一个可以在文档加载时调用的 JS“JavaInit”对象。 HTML 看起来有点像这样:

<html>
    <head>
        <script type='text/javascript' src="http://code.jquery.com/jquery-1.11.2.min.js"></script>
        <script type="text/javascript">

            DefaultInit = {
                init: function(x) {
                    return "Default init: " + x;
                }
            };

            $(function() {

                var text;
                if (window["JavaInit"] && JavaInit.init)
                    text = JavaInit.init("passed text");
                else
                    text = DefaultInit.init("passed text");

                $("#title").html(text);
            });

        </script>
    </head>
    <body>
        <h1 id="title"></h1>
    </body>
</html>

我在此处阅读了有关在页面加载事件之前设置 JS 成员的问题:javaFX webview window.onload is fired before loadworker succeeds ,所以我的 Java 代码如下所示:

public class Test extends Application {

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        WebView web = new WebView();
        Scene scene = new Scene(web, 400, 300);
        primaryStage.setScene(scene);
        primaryStage.show();
        initWeb(web);
    }

    private static void initWeb(WebView web) {

        WebEngine eng = web.getEngine();
        ((JSObject)eng.executeScript("window")).setMember("JavaInit", new JavaInit());

        URL url = Test.class.getResource("/test.html");
        eng.load(url.toString());
    }

    public static class JavaInit {

        public String init(Object o) {
            return "Java init: " + o;
        }
    }
}

它完全按照要求工作,但只有一次,在任何人调用“重新加载页面”之前。重新加载引擎似乎重新创建“窗口”对象并且所有注册成员都消失了。

可以将#setMember 放在“状态属性”监听器中:

private static void initWeb(WebView web) {

    WebEngine eng = web.getEngine();

    eng.getLoadWorker().stateProperty().addListener((val, oldState, newState) -> {
        if (newState == State.SUCCEEDED)
            ((JSObject)eng.executeScript("window")).setMember("JavaInit", new JavaInit());
    });

    URL url = Test.class.getResource("/test.html");
    eng.load(url.toString());
}

但是只有在触发 window.onload 之后才会调用它,并且一直调用默认的 init。这可以通过以最小延迟调用 init 代码来修复:

$(function() {

    setTimeout(function() {
        var text;
        if (window["JavaInit"] && JavaInit.init)
            text = JavaInit.init("passed text");
        else
            text = DefaultInit.init("passed text");

        $("#title").html(text);
    });
});

然后控制权从 JS 返回到 Java(如果存在),然后返回到已注册的函数,程序每次都能正常工作。

但似乎有点不对,创建 init delay 是希望 Java 能够成功注册所有成员。那么有人知道实现这种功能的“更合适”的方法吗?有没有可能在生产中需要更多时间,JS可以在成员注册之前调用延迟函数?或者是否有任何保证 WebEngine 将连续处理 Java 事件和 JS 执行?

谢谢!

最佳答案

我有同样的问题,我需要在 JS 中触发 onload 事件之前设置成员。我在标题中的 JS 中添加了警报:

    alert("command:inject");

在 Java 代码中:

    webEngine.setOnAlert(new EventHandler<WebEvent<String>>() {
        @Override
        public void handle(WebEvent<String> event) {
            // set members here
        }
    });

看起来,on alert handle 同步运行,所以当 onload 触发时,将启动的脚本将看到在 alert handler 中设置的成员

关于webview - JavaFX WebView 在重新加载时重新创建窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29892650/

相关文章:

android - Webview 无法正确显示 Facebook URL 的内容

javafx组合框项目列表问题

html - 防止浏览器在用户点击返回时重新加载页面

Javafx 2 单击并双击

javafx - javafx 中的上标和下标

python - 在 Python 中重新加载依赖模块

iOS - reloadData 时未调用 cellForRowAtIndexPath

javascript - 单击 Electron web View 中的元素

cocoa - 如何在加载页面之前清除 WebView 的内容?

react-native - React Native Webview如何使用injectJavascript