Skip to main content

句柄

介绍

Introduction

Playwright 可以创建页面 DOM 元素或页面内任何其他对象的句柄。这些句柄存在于 Playwright 进程中,而实际对象则存在于浏览器中。有两种类型的句柄:

Playwright can create handles to the page DOM elements or any other objects inside the page. These handles live in the Playwright process, whereas the actual objects live in the browser. There are two types of handles:

  • JSHandle 引用页面中的任何 JavaScript 对象

    JSHandle to reference any JavaScript objects in the page

  • ElementHandle 来引用页面中的 DOM 元素,它有额外的方法允许对元素执行操作并断言它们的属性。

    ElementHandle to reference DOM elements in the page, it has extra methods that allow performing actions on the elements and asserting their properties.

由于页面中的任何 DOM 元素也是 JavaScript 对象,因此任何 ElementHandle 也是 JSHandle

Since any DOM element in the page is also a JavaScript object, any ElementHandle is a JSHandle as well.

句柄用于对页面中的实际对象执行操作。你可以对句柄进行评估、获取句柄属性、将句柄作为评估参数传递、将页面对象序列化为 JSON 等。有关这些和方法,请参阅 JSHandle 类 API。

Handles are used to perform operations on those actual objects in the page. You can evaluate on a handle, get handle properties, pass handle as an evaluation parameter, serialize page object into JSON etc. See the JSHandle class API for these and methods.

API 参考

API reference

这是获得 JSHandle 的最简单方法。

Here is the easiest way to obtain a JSHandle.

const jsHandle = await page.evaluateHandle('window');
// Use jsHandle for evaluations.

元素句柄

Element Handles

劝阻

不鼓励使用 ElementHandle,而是使用 定位器 对象和 Web 优先断言。

The use of ElementHandle is discouraged, use Locator objects and web-first assertions instead.

当需要 ElementHandle 时,建议使用 page.waitForSelector()frame.waitForSelector() 方法获取。这些 API 等待元素被附加并可见。

When ElementHandle is required, it is recommended to fetch it with the page.waitForSelector() or frame.waitForSelector() methods. These APIs wait for the element to be attached and visible.

// Get the element handle
const elementHandle = page.waitForSelector('#box');

// Assert bounding box for the element
const boundingBox = await elementHandle.boundingBox();
expect(boundingBox.width).toBe(100);

// Assert attribute for the element
const classNames = await elementHandle.getAttribute('class');
expect(classNames.includes('highlighted')).toBeTruthy();

句柄作为参数

Handles as parameters

句柄可以传递到 page.evaluate() 和类似的方法中。以下代码片段在页面中创建一个新数组,使用数据对其进行初始化,并将该数组的句柄返回到 Playwright 中。然后它在后续评估中使用该句柄:

Handles can be passed into the page.evaluate() and similar methods. The following snippet creates a new array in the page, initializes it with data and returns a handle to this array into Playwright. It then uses the handle in subsequent evaluations:

// Create new array in page.
const myArrayHandle = await page.evaluateHandle(() => {
window.myArray = [1];
return myArray;
});

// Get the length of the array.
const length = await page.evaluate(a => a.length, myArrayHandle);

// Add one more element to the array using the handle
await page.evaluate(arg => arg.myArray.push(arg.newElement), {
myArray: myArrayHandle,
newElement: 2
});

// Release the object when it's no longer needed.
await myArrayHandle.dispose();

句柄生命周期

Handle Lifecycle

可以使用页面方法(例如 page.evaluateHandle()page.$()page.$$())或其对应的框架 frame.evaluateHandle()frame.$()frame.$$() 来获取句柄。创建后,句柄将保留 垃圾收集 中的对象,除非页面导航或通过 jsHandle.dispose() 方法手动处置句柄。

Handles can be acquired using the page methods such as page.evaluateHandle(), page.$() or page.$$() or their frame counterparts frame.evaluateHandle(), frame.$() or frame.$$(). Once created, handles will retain object from garbage collection unless page navigates or the handle is manually disposed via the jsHandle.dispose() method.

API 参考

API reference

Locator 与 ElementHandle

Locator vs ElementHandle

提醒

我们仅建议在极少数情况下(当你需要在静态页面上执行大量 DOM 遍历时)使用 ElementHandle。对于所有用户操作和断言,请改用定位器。

We only recommend using ElementHandle in the rare cases when you need to perform extensive DOM traversal on a static page. For all user actions and assertions use locator instead.

定位器ElementHandle 之间的区别在于后者指向特定元素,而 Locator 捕获如何检索该元素的逻辑。

The difference between the Locator and ElementHandle is that the latter points to a particular element, while Locator captures the logic of how to retrieve that element.

在下面的示例中,句柄指向页面上的特定 DOM 元素。如果该元素更改文本或被 React 使用来渲染完全不同的组件,则句柄仍然指向那个非常旧的 DOM 元素。这可能会导致意外的行为。

In the example below, handle points to a particular DOM element on page. If that element changes text or is used by React to render an entirely different component, handle is still pointing to that very stale DOM element. This can lead to unexpected behaviors.

const handle = await page.$('text=Submit');
// ...
await handle.hover();
await handle.click();

使用定位器,每次使用定位器时,都会使用选择器在页面中定位最新的 DOM 元素。因此,在下面的代码片段中,底层 DOM 元素将被定位两次。

With the locator, every time the locator is used, up-to-date DOM element is located in the page using the selector. So in the snippet below, underlying DOM element is going to be located twice.

const locator = page.getByText('Submit');
// ...
await locator.hover();
await locator.click();