List icon 目录

DOM

本指南描述了如何访问 DOM 文档、查找元素、修改 DOM 结构、模拟用户输入等。

概述

Browser 中加载的每个网页都有一个主 FrameFrame 本身可能有子 Frames。例如,当网页包含 IFRAME 元素时,需要使用 Frame 类来访问 DOM 和 JavaScript。

访问文档

每个 Frame 都有一个 DOM Document。要访问 Document,请使用 Frame.document() 方法:

Java
Kotlin

frame.document().ifPresent(document -> {});

val document = frame.document
document?.let {
}

查找元素

您可以根据不同的条件在元素中查找 HTML 元素。以下示例演示了如何查找文档元素内的所有 DIV 元素:

Java
Kotlin

document.documentElement().ifPresent(documentElement ->
    documentElement.findElementsByTagName("div").forEach(element -> {}));

val divs = document.documentElement!!.findElementsByTagName("div")
divs.forEach { element -> }

如果您只需要查找第一个 HTML 元素,请使用以下方法:

Java
Kotlin

documentElement.findElementByTagName("div").ifPresent(element -> {});

val div = documentElement.findByTagName("div")
div?.let {
}

以下是按不同条件搜索 HTML 元素的示例:

Java
Kotlin

documentElement.findElementsById("<id>");
documentElement.findElementsByName("<attr-name>");
documentElement.findElementsByTagName("<tag-name>");
documentElement.findElementsByClassName("<attr-class>");

documentElement.findElementsById("<id>")
documentElement.findElementsByName("<attr-name>")
documentElement.findElementsByTagName("<tag-name>")
documentElement.findElementsByClassName("<attr-class>")

XPath

JxBrowser DOM API 允许使用 Node.evaluate(String expression) 评估 XPath 表达式。您可以使用以下代码评估特定 Node 范围内的 XPath 表达式:

Java
Kotlin

try {
    var result = node.evaluate("count(//div)");
} catch (XPathException e) {
    // 无法评估给定的表达式。
}

val queryNumberOfDivs = XPathExpression("count(//div)")
try {
    val result: XPathResult = node.evaluate(queryNumberOfDivs)
} catch (e: XPathException) {
    // 无法评估给定的表达式。
}

当库无法计算给定表达式时,该方法会抛出 XPathException

评估结果存储在 XPathResult 对象中。请确保结果包含预期的值类型,例如 NumberBooleanStringNode,并提取该值本身:

Java
Kotlin

if (result.isNumber()) {
    double number = result.asNumber();
}

if (result.isNumber) {
    val number: Double = result.asNumber()
}

查询选择器

查找与指定选择器匹配的元素,如 #root,请使用以下代码:

Java
Kotlin

var elements = element.findElementsByCssSelector("#root");

val elements = element.findElementsByCssSelector("#root")

点上的节点

要在网页上找到特定点(例如 100x150 处)的 Node,请使用以下方法:

Java
Kotlin

var inspection = frame.inspect(Point.of(100, 150));
inspection.node().ifPresent(node -> {});

val inspection: PointInspection = frame.inspect(Point(100, 150))
val node: Node? = inspection.node

与元素交互

元素边界

您可以通过以下代码获取相对于当前 Document 视口左上角位置的 Element 的边界:

Java
Kotlin

var rect = element.boundingClientRect();

val rect = element.boundingClientRect()

这种方法在元素具有 hidden 属性或其 CSS 样式包含 display: none; 语句时将返回一个空的 Rect

元素属性

Element 类提供的方法允许您获取、添加、删除或修改 HTML 元素属性。以下示例演示如何获取元素的所有属性,并打印其名称和值:

Java
Kotlin

element.attributes().asMap().forEach((name, value) ->
    System.out.println(name + ": " + value));

element.attributes.asMap().forEach { (name, value) ->
    println("$name: $value")
}

以下示例演示如何添加/修改元素属性:

Java
Kotlin

element.attributes().put("attrName", "attrValue");

element.attributes["attrName"] = "attrValue"

创建元素

DOM API 允许修改文档 DOM 结构。以下示例演示了如何创建和插入带有一些文本的 <p> 元素:

Java
Kotlin

// 创建一个新的段落元素。
var paragraph = document.createElement("p");
// 创建一个包含给定文本的文本节点。
var text = document.createTextNode("Text");
// 将文本节点插入到段落元素中。
if (paragraph.appendChild(text)) {
    // 将段落元素插入到所需的元素中。
    boolean success = element.appendChild(paragraph);
}

// 创建一个新的段落元素。
val paragraph = document.createElement("p")
// 创建一个包含给定文本的文本节点。
val text = document.createTextNode("Text")
// 将文本节点插入到段落元素中。
if (paragraph.appendChild(text)) {
    // 将段落元素插入到所需的元素中。
    val success = element.appendChild(paragraph)
}

关闭节点

具有 Node 对应物的 DOM 对象不会受到 Blink 垃圾回收机制的自动处理。默认情况下,我们会将这些对象保留在内存中,直到页面被卸载。

为了优化内存使用,您可以基于每个对象启用垃圾回收:

Java
Kotlin

node.close();

node.close()

关闭 Node 会将相应的 Blink 对象标记为可回收对象,但不会立即释放该对象。在调用 close() 方法后,尝试使用 Node 将导致 ObjectClosedException

DOM 事件

每个 Node 都实现了 EventTarget 接口,该接口提供了用于注册 DOM 事件的方法。您可以注册 DOM 监听器来接收 DOM 事件,例如 clickmousedownmouseupkeydownloaderror 等。

以下示例演示了如何为文档 HTML 元素注册点击事件监听器:

Java
Kotlin

document.documentElement().ifPresent(element ->
    element.addEventListener(EventType.CLICK, event -> {
        // 鼠标点击事件已被接收。
        if (event instanceof MouseEvent) {
            var mouseEvent = (MouseEvent) event;
            var clickCount = mouseEvent.clickCount();
        }
    }, false));

val listener = Observer<Event> { event ->
    // 鼠标点击事件已被接收。
    if (event is MouseEvent) {
        val clickCount = event.clickCount()
    }
}
val useCapture = false
document.documentElement?.addEventListener(
    EventType.CLICK,
    listener,
    useCapture
)

此外,JxBrowser 还允许您监听自定义 DOM 事件并访问其数据载荷。

Java
Kotlin

// 创建自定义的 DOM 事件类型。
var eventType = EventType.of("MyEvent");
// 监听给定事件类型的事件。
element.addEventListener(eventType, event -> {
    // 已收到 MyEvent 事件。
    if (event instanceof CustomEvent) {
        var customEvent = (CustomEvent) event;
        var payload = customEvent.detail();
    }
}, false);

// 创建自定义的 DOM 事件类型。
val eventType = EventType.of("MyEvent")
val listener = Observer<Event> { event ->
    // 已收到 MyEvent 事件。
    if (event is CustomEvent) {
        val payload = event.detail<JsObject>()
    }
}
val useCapture = false
// 监听给定事件类型的事件。
element.addEventListener(eventType, listener, useCapture)

自动化

JxBrowser DOM API 提供了自动填写 Wed 表单所需的一切。本节介绍如何更新文本字段中的文本、选择复选框或单选按钮、在下拉列表中选择一个或多个选项、模拟单击等。

要使用 Web 表单控件,请使用 FormControlElement 接口。此接口允许检查控件是否启用,并修改其值。所有的表单控件,如 INPUTSELECTTEXTAREA 等都继承了这个接口。

输入

要使用 INPUT 元素,请使用 InputElement接口。 它提供了检查输入类型和设置其值所需的所有方法。

文本、邮箱、密码

要用新值替换文本、邮箱或密码字段的默认值,请使用 InputElement.value(String) 方法。

例如,如果您的 Web 表单包含以下类型的 <input> 元素:

<input type="text" id="firstname" placeholder="名字">
<input type="email" id="email" placeholder="邮箱地址">
<input type="password" id="password" placeholder="密码">

您可以使用以下方法设置它们的值:

Java
Kotlin

documentElement.findElementById("firstname").ifPresent(element ->
    ((InputElement) element).value("John"));

documentElement.findElementById("email").ifPresent(element ->
    ((InputElement) element).value("me@company.com"));

documentElement.findElementById("password").ifPresent(element ->
    ((InputElement) element).value("Jkdl12!"));

val firstname = documentElement.findById("firstname") as InputElement
firstname.value = "John"

val email = documentElement.findById("email") as InputElement
email.value = "me@company.com"

val password = documentElement.findById("password") as InputElement
password.value = "Jkd12!"

复选框、单选按钮

要选中单选按钮或复选框,请使用 InputElement.check() 方法。

例如,如果您的 Web 表单包含以下类型的 <input> 元素:

<input type="checkbox" id="checkbox" value="记住我">
<input type="radio" id="radio" checked>

您可以使用以下方法选择/取消选择它们:

Java
Kotlin

documentElement.findElementById("checkbox").ifPresent(element ->
    ((InputElement) element).check());

documentElement.findElementById("radio").ifPresent(element ->
    ((InputElement) element).uncheck());

val checkbox = documentElement.getById("checkbox") as InputElement
checkbox.check()

val radio = documentElement.getById("radio") as InputElement
radio.uncheck()

文件

<input> 元素中的 type=file 允许用户从其设备存储中选择一个或多个文件。JxBrowser 允许您通过编程方式选择文件并更新 <input type=file> 元素的值。

例如,如果您的 Web 表单包含一个 <input> 元素,如下所示:

<input type="file" id="avatar" accept="image/png, image/jpeg" multiple>

您可以使用以下方法通过编程选择所需的一个或多个文件:

Java
Kotlin

documentElement.findElementById("avatar").ifPresent(element ->
    ((InputElement) element).file("file1.png", "file2.jpeg"));

val avatar = documentElement.getById("avatar") as InputElement
avatar.file("file1.png", "file2.png")

文本区

要在 <textarea> 元素中设置文本,例如:

<textarea id="details"></textarea>

请使用以下方法:

Java
Kotlin

documentElement.findElementById("details").ifPresent(element ->
    ((TextAreaElement) element).value("Some text..."));

val details = documentElement.getById("details") as TextAreaElement
details.value = "Some text..."

选择 & 选项

要选择 SELECT 控件中的所有选项,例如:

<select id="fruits" multiple>
    <option>苹果</option>
    <option>橘子</option>
    <option>菠萝</option>
    <option>香蕉</option>
</select>

请使用以下方法:

Java
Kotlin

documentElement.findElementById("fruits").ifPresent(element -> {
    var selectElement = (SelectElement) element;
    selectElement.options().forEach(optionElement ->
        optionElement.select());
});

val fruits = documentElement.getById("fruits") as SelectElement
fruits.options.forEach {
    it.select()
}

使用这种方法,您可以只选择一个所需的选项。

模拟点击

要模拟鼠标点击某个元素,请使用以下方法:

Java
Kotlin

element.click();

element.click()

click() 与受支持的元素(例如 <input>)一起使用时,它会触发元素的点击事件。然后该事件会冒泡到文档树中更高层级的元素,并触发它们的点击事件。

分发事件

您可以使用 EventTarget.dispatch(Event) 方法在指定的 EventTarget 上分发一个 Event

以下示例演示了如何在指定的元素上分发标准的 click 事件:

Java
Kotlin

// 客户端和屏幕位置。
var location = Point.of(10, 10);
// 创建具有所需选项的 MouseEvent。
var mouseClickEvent = document.createMouseEvent(EventType.CLICK,
    MouseEventParams.newBuilder()
        // 主按钮按下。
        .button(MouseEvent.Button.MAIN)
        .clientLocation(location)
        .screenLocation(location)
        .uiEventModifierParams(
            UiEventModifierParams.newBuilder()
                .eventParams(EventParams.newBuilder()
                    .bubbles(true)
                    .cancelable(true)
                    .build())
                .build())
        .build());
// 在目标元素上生成点击事件。
element.dispatch(mouseClickEvent);

// 客户端和屏幕位置。
val location = Point(10, 10)
// 创建具有所需选项的 MouseEvent。
val eventParams = EventParams(bubbles = true, cancelable = true)
val uiEventModifiers = UiEventModifierParams(eventParams)
val mouseEventParams = MouseEventParams(
    button = MouseEvent.Button.MAIN,  // 主按钮按下。
    location = location,
    locationOnScreen = location,
    uiEventModifierParams = uiEventModifiers
)
val mouseClickEvent = document.createMouseEvent(
    EventType.CLICK,
    mouseEventParams
)
// 在目标元素上生成点击事件。
element.dispatch(mouseClickEvent)

使用这种方法,您可以创建和分发各种 DOM 事件。此类事件通常称为合成事件,与 Browser 本身触发的事件相对。