JavaFX WebView:使用loadContent()链接到文档中的锚点不起作用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaFX WebView:使用loadContent()链接到文档中的锚点不起作用相关的知识,希望对你有一定的参考价值。

注意:这是关于JavaFX WebView,而不是android WebView(即我见过“Android Webview Anchor Link (Jump link) not working”)。


我在javafx.scene.web.WebView中显示一个生成的html页面,其中包含锚点和链接到这些锚点,如下所示:

<p>Jump to <a href="#introduction">Introduction</a></p>
some text ...
<h1 id="introduction">Introduction</h1>
more text ...

我使用此代码将HTML加载到WebView中:

public void go(String location) {
    try {
        // read the content into a String ...
        String html = NetUtil.readContent(new URL(location), StandardCharsets.UTF_8);
        // ... and use loadContent()
        webview.getEngine().loadContent(html);
    } catch (IOException e) {
        LOG.error(e);
    }
}

一切都正确呈现,但如果我点击名为“简介”的链接,没有任何反应。

然而,HTML是正确的,我使用此代码检查了它:

public void go(String location) {
    // use load() to directly load the URL
    webview.getEngine().load(location);
}

现在,一切正常。

问题似乎是某种程度上因为WebView的文档URL在使用null时是loadContent(),但由于它是一个只读属性,我不知道如何使它工作。

我需要使用loadContent(),因为HTML是动态生成的,如果可能的话,我不想将其写入文件只是为了使锚链接工作。有没有办法来解决这个问题?


编辑我为JavaFX提交了bug

答案

这可能是另一个WebEngine错误。很多代码只是包含在api中的本机库,因此我们无法在运行时修改它来修复一些残障。

如果您能够更改生成文件的结构,则可以在js中实现滚动到元素:

<script>
function scrollTo(elementId) {
    document.getElementById(elementId).scrollIntoView(); 
}
</script>

<a href='#' onclick=scrollTo('CX')>Jump to Chapter X</a>
<h2 id="CX">Chapter X</h2>

如果你不能改变结构,我已经采取了一些步骤来尝试修复它和一些建议 - 首先我在location之后通过反射确定loadContent的值:

Field locationField = WebEngine.class.getDeclaredField("location");
locationField.setAccessible(true);

ReadOnlyStringWrapper location = (ReadOnlyStringWrapper) locationField.get(engine);
location.set("local");

但事实上,保持实际位置的状态只是一个信息给你,操纵这个改变没有。我也找到了一种从js设置url的方法(只是一个很长的镜头,我们没有任何具体的细节,为什么它不工作):

window.history.pushState("generated", "generated", '/generated');

当然我们不能因为:

SecurityError: DOM Exception 18: An attempt was made to break through the security policy of the user agent.

我想你应该忘记loadContent()。你说你不想把生成的内容写到文件中。有点脏的黑客,但真的对你有帮助可以在你的应用程序中随机和未使用的端口包装http服务器。你甚至不需要外部库,因为Java有这样简单的实用程序:

HttpServer server = HttpServer.create(new InetSocketAddress(25000), 0);
server.createContext("/generated", httpExchange -> {
    String content = getContent();
    httpExchange.sendResponseHeaders(200, content.length());
    OutputStream os = httpExchange.getResponseBody();
    os.write(content.getBytes());
    os.close();
});

server.setExecutor(null);
server.start();

您还可以使用其他浏览器来显示您的网页,例如JCEF(Java Chromium Embedded Framework)。

以上是关于JavaFX WebView:使用loadContent()链接到文档中的锚点不起作用的主要内容,如果未能解决你的问题,请参考以下文章

使用 javafx 从 webview 获取内容

JavaFX : 使用 JavaFX 嵌入浏览器而不是可用的 webview

为啥JavaFX的WebView是红绿闪烁?

JavaFX 中 WebView 的性能

JavaFx:打开另外一个窗体并加载WebView

JavaFX - 如何创建(不可见)WebView 的快照/屏幕截图