DOM

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

概述

Browser 中加载的每个网页都有一个主 FrameFrame 本身可能有子框架。 例如,当网页有 IFRAMEs 时,请使用 Frame 类来访问 DOM 和 JavaScript。

访问文档

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

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

查找元素

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

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

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

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

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

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 表达式:

try {
    XPathResult result = node.evaluate("count(//div)");
} catch (XPathException e) {
    // Failed to evaluate the given expression.
}
try {
    val result: XPathResult = node.evaluate("count(//div)")
} catch (e: XPathException) {
    // Failed to evaluate the given expression.
}

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

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

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

查询选择器

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

List<Element> elements = element.findElementsByCssSelector("#root");
val elements = element.findElementsByCssSelector("#root")

点上的节点

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

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

使用元素

元素边界

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

Rect rect = element.boundingClientRect();
val rect = element.boundingClientRect()

当元素具有 hidden 属性或元素的CSS样式包含 display: none;语句时,该方法返回一个空的 Rect

元素属性

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

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

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

element.putAttribute("attrName", "attrValue");
element.putAttribute("attrName", "attrValue")

创建元素

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

// Create a new paragraph element.
Element paragraph = document.createElement("p");
// Create a text node with the given text.
Node text = document.createTextNode("Text");
// Insert the text node into the paragraph element.
if (paragraph.appendChild(text)) {
    // Insert the paragraph element into the required element.
    boolean success = element.appendChild(paragraph);
}
// Create a new paragraph element.
val paragraph = document.createElement("p")
// Create a text node with the given text.
val text = document.createTextNode("Text")
// Insert the text node into the paragraph element.
if (paragraph.appendChild(text)) {
    // Insert the paragraph element into the required element.
    success = element.appendChild(paragraph)
}

垃圾回收

具有 Node 对应物的 DOM 对象不受 Blink 垃圾回收的影响。 默认情况下,我们将这些对象保留在内存中,直到页面被卸载。 为了优化内存使用,您可以在每个对象的基础上启用垃圾回收:

node.close();
node.close()

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

DOM 事件

每个 Node 都实现 EventTarget 接口,该接口提供注册 DOM 事件的方法。 您可以注册 DOM 监听器以接收 DOM 事件,例如 click, mousedown, mouseup, keydown, load, error 等。

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

document.documentElement().ifPresent(element ->
        element.addEventListener(EventType.CLICK, event -> {
            // Mouse click event has been received.
            if (event instanceof MouseEvent) {
                MouseEvent mouseEvent = (MouseEvent) event;
                int clickCount = mouseEvent.clickCount();
            }
        }, false));
document.documentElement().ifPresent { element ->
    element.addEventListener(EventType.CLICK, { event ->
            // Mouse click event has been received.
            if (event is MouseEvent) {
                val clickCount = event.clickCount()
            }
        }, false
    )
}

此外,JxBrowser 允许您监听自定义 DOM 事件并访问它们的负载:

// Create a custom DOM event type.
EventType eventType = EventType.of("MyEvent");
// Listen to the events of the given event type.
element.addEventListener(eventType, event -> {
    // The MyEvent event has been received.
    if (event instanceof CustomEvent) {
        CustomEvent customEvent = (CustomEvent) event;
        JsObject payload = customEvent.detail();
    }
}, false);
// Create a custom DOM event type.
val eventType = EventType.of("MyEvent")
// Listen to the events of the given event type.
element.addEventListener(eventType, { event ->
    // The MyEvent event has been received.
    if (event is CustomEvent) {
        val payload = event.detail<JsObject>()
    }
}, false)

自动化

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

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

输入

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

文本、邮箱、密码

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

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

<input type="text" id="firstname" placeholder="First Name">
<input type="email" id="email" placeholder="Email Address">
<input type="password" id="password" placeholder="Password">

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

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!"));
documentElement.findElementById("firstname").ifPresent { element ->
        (element as InputElement).value("John")
}

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

documentElement.findElementById("password").ifPresent { element ->
        (element as InputElement).value("Jkdl12!")
}

复选框、单选按钮

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

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

<input type="checkbox" id="checkbox" value="Remember me">
<input type="radio" id="radio" checked>

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

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

documentElement.findElementById("radio").ifPresent(element ->
        ((InputElement) element).uncheck());
documentElement.findElementById("checkbox").ifPresent { element ->
        (element as InputElement).check()
}

documentElement.findElementById("radio").ifPresent { element ->
        (element as InputElement).uncheck()
}

文件

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

例如,如果您的网页表单包含一个 <input> 元素,例如:

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

您可以使用以下方法以编程方式选择所需的文件:

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

文本区

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

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

请使用以下方法:

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

选择 & 选项

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

<select id="fruits" multiple>
    <option>Apple</option>
    <option>Orange</option>
    <option>Pineapple</option>
    <option>Banana</option>
</select>

请使用以下方法:

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

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

模拟点击

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

element.click();
element.click()

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

派发事件

您可以使用EventTarget.dispatch(Event) 方法在特定的 EventTarget 处派发 Event

以下示例演示了如何在特定元素处派发标准 click 事件:

// Client and screen location.
Point location = Point.of(10, 10);
// Create MouseEvent with the required options.
MouseEvent mouseClickEvent = document.createMouseEvent(EventType.CLICK,
        MouseEventParams.newBuilder()
                // The main button pressed.
                .button(Button.MAIN)
                .clientLocation(location)
                .screenLocation(location)
                .uiEventModifierParams(
                        UiEventModifierParams.newBuilder()
                                .eventParams(EventParams.newBuilder()
                                        .bubbles(true)
                                        .cancelable(true)
                                        .build())
                                .build())
                .build());
// Generate a click event on the target element.
element.dispatch(mouseClickEvent);
// Client and screen location.
val location = Point.of(10, 10)
// Create MouseEvent with the required options.
val mouseClickEvent = document.createMouseEvent(EventType.CLICK,
        MouseEventParams.newBuilder()
                // The main button pressed.
                .button(Button.MAIN)
                .clientLocation(location)
                .screenLocation(location)
                .uiEventModifierParams(
                        UiEventModifierParams.newBuilder()
                                .eventParams(EventParams.newBuilder()
                                        .bubbles(true)
                                        .cancelable(true)
                                        .build())
                                .build())
                .build())
// Generate a click event on the target element.
element.dispatch(mouseClickEvent)

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

Go Top