简体   繁体   English

JavaFX WebView:链接到文档中的锚点无法使用 loadContent()

[英]JavaFX WebView: link to anchor in document doesn't work using loadContent()

Note: This is about JavaFX WebView, not Android WebView (ie I have seen " Android Webview Anchor Link (Jump link) not working ").注意:这是关于 JavaFX WebView,而不是 Android WebView(即我已经看到“ Android Webview 锚链接(跳转链接)不起作用”)。


I display a generated HTML page inside a javafx.scene.web.WebView that contains anchors and links to those anchors like this:我在javafx.scene.web.WebView中显示一个生成的 HTML 页面,其中包含锚点和指向这些锚点的链接,如下所示:

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

I use this code to load the HTML into the WebView:我使用此代码将 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);
    }
}

Everything is rendered correctly, but if I click on the link named "Introduction", nothing happens.一切都正确呈现,但如果我单击名为“介绍”的链接,则没有任何反应。

The HTML however is correct, which I checked by instead using this code:然而,HTML 是正确的,我使用以下代码进行了检查:

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

Now, everything worls fine.现在,一切正常。

The problem seems to be somehow because the document URL of the WebView is null when using loadContent() , but since it's a readonly property, I have no idea how to make it work.问题似乎是因为 WebView 的文档 URL 在使用loadContent()时为null ,但由于它是只读属性,我不知道如何使其工作。

I need to use loadContent() , because the HTML is generated on the fly, and if possible in any way, I don't want to have to write it out to a file just to make anchor links working.我需要使用loadContent() ,因为 HTML 是动态生成的,如果可能的话,我不想为了使锚链接工作而将它写到文件中。 Is there a way to fix this?有没有办法来解决这个问题?


EDIT I filed a bug for JavaFX.编辑我为 JavaFX 提交了一个错误

It's probably another WebEngine bug .这可能是另一个 WebEngine错误 A lot of that code is just a native libraries wrapped in api, so we can't modify it in runtime to fix some disabilities.很多代码只是封装在 api 中的本机库,因此我们无法在运行时修改它以修复某些缺陷。

If you are able to change the structure of generated file you can implement scrolling to element in js:如果您能够更改生成文件的结构,您可以在 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>

If you can't change the structure, there is some steps that I've made to try to fix it and some suggestions - at first I've set value of location by reflections after loadContent for sure:如果你不能改变结构,我已经采取了一些步骤来尝试修复它并提出一些建议 - 首先我肯定在loadContent之后通过反射设置了location的值:

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

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

But in fact, keeping state of actual location is just an information for you and manipulating this changes nothing.但事实上,保持实际位置的状态只是给你的一个信息,操纵它没有任何改变。 I've also found a way to set url from js (just a long shot, we don't have any specific details why it's not working):我还找到了一种从 js 设置 url 的方法(只是一个远景,我们没有任何具体细节为什么它不起作用):

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

Of course we can't because of:我们当然不能,因为:

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

I think you should forget about loadContent() .我认为你应该忘记loadContent() You said that you didn't want to write generated content to file.您说您不想将生成的内容写入文件。 A little dirty hack but really helpful for you could be wrapped http server on random and unused port in your application.有点脏,但对您真的很有帮助,可以将 http 服务器包装在您的应用程序中的随机和未使用的端口上。 You don't even need external libraries because Java has simple utilities like that:你甚至不需要外部库,因为 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();

You can also use another browser to display your page, eg JCEF ( Java Chromium Embedded Framework ).您还可以使用其他浏览器来显示您的页面,例如JCEFJava Chromium Embedded Framework )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM