在loadworker成功之前触发javaFX webview window.onload

时间:2014-08-20 12:32:32

标签: webview javafx onload

我在我的应用程序中使用JavaFX webview。使用以下代码,我在页​​面加载后设置了一个成员

webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
    @Override
    public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
        if (newState == Worker.State.SUCCEEDED) {
            JSObject window = (JSObject) webEngine.executeScript("window");
            window.setMember("mymember", new JavaScriptBridge(this));
        }
    }
});

现在在javascript中,我可以调用mymember.doSomething(),例如当我按下按钮并且它已成功执行时调用,但是如果我将以下代码添加到html

<script>
function startup() {
    mymember.doSomething();
}
window.onload=startup;
</script>

加载页面时不会自动执行。似乎window.onloadLoadWorker收到通知之前执行。所以mymember尚未确定。但另一方面,我在加载html之前无法设置mymember,对吗?

当我需要设置mymember以便在执行window.onload时准备就绪时,有什么想法吗?

谢谢!

3 个答案:

答案 0 :(得分:3)

对于这个问题的答案可能为时已晚,但在回答this问题之后,我一直试图找到在完全加载网页后必须调用executeScript的原因。

所以我做了这个测试:

    public class EarlyWebEngineTest extends Application {

    @Override
    public void start(Stage stage) {
        final WebView webView = new WebView();
        final WebEngine webEngine = webView.getEngine();

        // Early call of executeScript to get a JavaScript object, a proxy for the 
        // Java object to be accessed on the JavaScript environment
        JSObject window = (JSObject) webEngine.executeScript("window");
        window.setMember("app", new JavaApplication());

        webEngine.getLoadWorker().stateProperty().addListener((ov,oldState,newState)->{
            if(newState==State.SCHEDULED){
                System.out.println("state: scheduled");
            } else if(newState==State.RUNNING){
                System.out.println("state: running");
            } else if(newState==State.SUCCEEDED){
                System.out.println("state: succeeded");
            }
        });

        Button button=new Button("Load Content");
        button.setOnAction(e->webEngine.loadContent("<html>"
                + " <script>function initialize() {"
                + " var nameVar = \"This is a JS var\"; " 
                + " app.callJavascript(nameVar);"
                + "} </script>"
                + "    <body onLoad=\"initialize()\">Hi, this is a test!</body>"
                + "</html>"));

        VBox vbox = new VBox(10,button,webView);
        Scene scene = new Scene(vbox,400,300);

        stage.setScene(scene);
        stage.show();

    }

    public class JavaApplication {

        public void callJavascript(String msg){
            System.out.println("JS>> "+msg);
        }
    }

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

}

在单击按钮之前不会加载内容,但我们已经在浏览器上创建了JavaScript对象。

在单击按钮之前,输出控制台上没有任何内容。但是如果我们点击按钮......这就是输出:

state: scheduled
state: running
JS>> This is a JS var
state: succeeded

正如我们所看到的,Java对象在执行后者之前被有效地传递给脚本,并且在加载内容时成功调用了app.callJavascript

请注意,出于访问加载的DOM的常见目的,在executeScript之后调用State.SUCCEEDED的常用方法仍然是推荐方法。

答案 1 :(得分:2)

所有(包括后续)页面的工作: 在Java代码中设置了“ java”的地方:

window.setMember("java", new JavaApplication());

HTML(后续)页面,如果未设置var“ java”(JAVA外部),请等待100毫秒:

 <script>                   
        function init(){
            if (typeof java !== 'undefined') {
                java.doSomething();
            }else{
                setTimeout(function(){ init() }, 100 );
            }
        }

        $(document).ready(function(){           
            init();         
        });
    </script> 

答案 2 :(得分:0)

是的,loadworker总是在window.onloaddocument.onload之后执行。

您可以尝试的解决方法,可以在javascript中创建新的侦听器,例如所谓的:

document.addEventListener("deviceready", function(){
    MyJavaBridge.executeJavaMethod();
});

然后在您的loadworker中,可以执行以下操作:

webview.getEngine().getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> {
            
    if (newState == Worker.State.SUCCEEDED) {
        JSObject window = (JSObject) webview.getEngine().executeScript("window");
        System.out.println("window : " + window);
        window.setMember("MyJavaBridge", javaBridge);
        
        webview.getEngine().executeScript("const event = new Event('deviceready');document.dispatchEvent(event);");
    }
});

如您所见,您可以在webview.getEngine().executeScript("const event = new Event('deviceready');document.dispatchEvent(event);");之后执行setMember,因此可以在自定义事件监听器window.onload中进行操作,而不必在deviceready中初始化工作,因此您可以更好地控制页面加载和Java端loadworker的顺序。

这正是科尔多瓦的做法,这个想法源于它。

JQuery document.ready vs Phonegap deviceready