我在我的应用程序中使用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.onload
在LoadWorker
收到通知之前执行。所以mymember
尚未确定。但另一方面,我在加载html之前无法设置mymember
,对吗?
当我需要设置mymember
以便在执行window.onload
时准备就绪时,有什么想法吗?
谢谢!
答案 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.onload
或document.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的顺序。
这正是科尔多瓦的做法,这个想法源于它。