句柄
介绍
🌐 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 对象
- ElementHandle 用于引用页面中的 DOM 元素,它具有额外的方法,可对这些元素执行操作并断言它们的属性。
由于页面中的任何 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.
- Sync
- Async
js_handle = page.evaluate_handle('window')
# Use jsHandle for evaluations.
js_handle = await page.evaluate_handle('window')
# Use jsHandle for evaluations.
元素句柄
🌐 Element Handles
不鼓励使用 ElementHandle,请改用 Locator 对象和以网页为先的断言。
🌐 The use of ElementHandle is discouraged, use Locator objects and web-first assertions instead.
当需要 ElementHandle 时,建议使用 page.wait_for_selector() 或 frame.wait_for_selector() 方法来获取它。这些 API 会等待元素被附加并可见。
🌐 When ElementHandle is required, it is recommended to fetch it with the page.wait_for_selector() or frame.wait_for_selector() methods. These APIs wait for the element to be attached and visible.
- Sync
- Async
# Get the element handle
element_handle = page.wait_for_selector('#box')
# Assert bounding box for the element
bounding_box = element_handle.bounding_box()
assert bounding_box.width == 100
# Assert attribute for the element
class_names = element_handle.get_attribute('class')
assert 'highlighted' in class_names
# Get the element handle
element_handle = page.wait_for_selector('#box')
# Assert bounding box for the element
bounding_box = await element_handle.bounding_box()
assert bounding_box.width == 100
# Assert attribute for the element
class_names = await element_handle.get_attribute('class')
assert 'highlighted' in class_names
句柄作为参数
🌐 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:
- Sync
- Async
# Create new array in page.
my_array_handle = page.evaluate_handle("""() => {
window.myArray = [1];
return myArray;
}""")
# Get current length of the array.
length = page.evaluate("a => a.length", my_array_handle)
# Add one more element to the array using the handle
page.evaluate("(arg) => arg.myArray.push(arg.newElement)", {
'myArray': my_array_handle,
'newElement': 2
})
# Release the object when it's no longer needed.
my_array_handle.dispose()
# Create new array in page.
my_array_handle = await page.evaluate_handle("""() => {
window.myArray = [1];
return myArray;
}""")
# Get current length of the array.
length = await page.evaluate("a => a.length", my_array_handle)
# Add one more element to the array using the handle
await page.evaluate("(arg) => arg.myArray.push(arg.newElement)", {
'myArray': my_array_handle,
'newElement': 2
})
# Release the object when it's no longer needed.
await my_array_handle.dispose()
句柄生命周期
🌐 Handle Lifecycle
句柄可以通过页面方法获取,例如 page.evaluate_handle()、page.query_selector() 或 page.query_selector_all(),或者它们的框架对应方法 frame.evaluate_handle()、frame.query_selector() 或 frame.query_selector_all()。创建后,句柄将保留对象,防止被垃圾回收,除非页面导航或通过 js_handle.dispose() 方法手动释放句柄。
🌐 Handles can be acquired using the page methods such as page.evaluate_handle(), page.query_selector() or page.query_selector_all() or their frame counterparts frame.evaluate_handle(), frame.query_selector() or frame.query_selector_all(). Once created, handles will retain object from garbage collection unless page navigates or the handle is manually disposed via the js_handle.dispose() method.
API 参考
🌐 API reference
- JSHandle
- ElementHandle
- element_handle.bounding_box()
- element_handle.get_attribute()
- element_handle.inner_text()
- element_handle.inner_html()
- element_handle.text_content()
- js_handle.evaluate()
- page.evaluate_handle()
- page.query_selector()
- page.query_selector_all()
Locator 与 ElementHandle
🌐 Locator vs ElementHandle
我们仅建议在需要对静态页面进行大量 DOM 遍历的少数情况下使用 ElementHandle。对于所有用户操作和断言,请改用定位器 (locator)。
🌐 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.
Locator 和 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.
在下面的示例中,handle 指向页面上的特定 DOM 元素。如果该元素的文本发生变化,或者被 React 用来渲染一个完全不同的组件,handle 仍然指向那个已经过时的 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.
- Sync
- Async
handle = page.query_selector("text=Submit")
handle.hover()
handle.click()
handle = await page.query_selector("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.
- Sync
- Async
locator = page.get_by_text("Submit")
locator.hover()
locator.click()
locator = page.get_by_text("Submit")
await locator.hover()
await locator.click()