我正在尝试在基于JavaFX的UI中使用webview。每当某些操作发生时,必须通过调用.load(...)
方法来更改webview的内容。每次加载后,我必须在webview中的窗口对象上设置一些不同的值。然后将这些值用在JavaScript代码中,该代码使用jQuery在文档的ready事件上运行:
$(document).ready(function() {
// here I use values set on window to populate/manipulate HTML elements
});
我正在按照Oracle的指南获取窗口对象,并在其上使用setMember
来传递我需要的值here。但是,当第一次调用webView.load
时,与之后调用时相比,我遇到了不一致的问题。问题是,第一次可以在加载内容之前在窗口对象上设置值。这意味着JavaScript将拥有所需的数据。然而,在随后的调用中,我找不到在正确的时刻设置值的方法。这些值要么在旧窗口对象上设置得太早,要么在文档更改后删除,或者设置得太晚,在 JavaScript完成运行后。
我尝试在webView.getEngine().getLoadWorker().stateProperty().addListener(...)
和webEngine.documentProperty().addListener(...)
设置值,前者太早,后者太晚。
我找到了一个解决方案,在webEngine.documentProperty().addListener(...)
上调用显式JavaScript函数。但这阻止了我在Web和Java项目之间共享相同的UI。重要的是找到一种方法来解决这个(我想说的)错误并具有适当的一致功能。
我知道之前已经提出了类似的问题,但对于非这些问题,与网络上的行为完全相同并不重要。
更新 添加一个小例子来进一步澄清问题:
public class WebEngineLoadBug extends Application {
private WebEngine webEngine;
private WebView webView;
/**
* @param args ignored.
*/
public static void main(final String[] args) {
launch(args);
}
@Override
public void start(final Stage primaryStage) throws Exception {
webView = new WebView();
webEngine = webView.getEngine();
// alert is the safest way to pass on data
webEngine.setOnAlert(new EventHandler<WebEvent<String>>() {
@Override
public void handle(WebEvent<String> event) {
System.out.println(event.getData());
}
});
primaryStage.setScene(new Scene(webView));
primaryStage.show();
load1();
}
public void load2() {
System.out.println("loading 2 ...");
// second load
JSObject dom2Window = (JSObject) webEngine.executeScript("window");
dom2Window.setMember("variable2Name", "variable value 2");
dom2Window.setMember("ctr", this);
// this load does NOT work as expected, variable2Name is NOT set before JavaScript runs and it can NOT be accessed in document ready event
webEngine.load(WebEngineLoadBug.class.getResource("/file2.html").toExternalForm());
}
public void load1() {
System.out.println("loading 1 ...");
// first load
JSObject domWindow = (JSObject) webEngine.executeScript("window");
domWindow.setMember("variableName", "variable value 1");
domWindow.setMember("ctr", this);
// this load works perfectly, variableName is set before JavaScript runs and it can be accessed in document ready event
webEngine.load(WebEngineLoadBug.class.getResource("/file1.html").toExternalForm());
}
}
这是file1.html
:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.2.1.min.js"></script>
</head>
<body>
<h1 id="title">FILE 1</h1>
<a href="#" onclick="event.preventDefault(); ctr.load2();">load 2</a>
<script>
alert('file1');
$(document).ready(function () {
// use variableName here
$("#title").html(variableName);
alert(variableName);
});
</script>
</body>
</html>
来file2.html
:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.2.1.min.js"></script>
</head>
<body>
<h1 id="title">FILE 2</h1>
<a href="#" onclick="event.preventDefault(); ctr.load1();">load 1</a>
<script>
alert('file2');
$(document).ready(function () {
// use variableName here
$("#title").html(variable2Name);
alert(variable2Name);
});
</script>
</body>
</html>
问题在控制台上可见,您将看到这些行:
loading 1 ...
file1
variable value 1
loading 2 ...
file2
问题是此处缺少variable value 2
,并且未加载第二页的标题。即使您向前和向后导航到页面,您也会看到值不再正确传递。