我正在创建一个页面,该页面将在 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 中设置的成员


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!