Playwright默认的locator不支持直接访问iframe,当然xpath可以,不过我们既然用playwright自然是看上了它的优雅等待。
目前很多后台管理系统,实际是菜单+嵌入一个iframe实现的(特别是跨架构、跨系统的,也有用qiankun、wujie等微前端框架嵌入的)
我们通过page.main_frame.child_frames获取frame时,发现只能获取到主页刚加载时第一个farme,无法获取新打开的菜单
因为后台管理系统默认会进入第一个页面,当我们点击菜单进入其他页面时,上一个iframe还没来得及销毁,且因为我们点击菜单的入口连接元素,元素本身是稳定的(Playwright的优雅等待实在是不会浪费1秒钟)就进入下一个操作了,这时候iframe的状态是不会影响我们进入新的菜单的,但会影响到我们后续针对进入菜单后执行的业务操作。
通过page.frame ()或者上面的变量(page.main_frame.child_frames)进行获取页面frame时,会发现获取不到新页面的iframe,因为这时候上一个frame还没销毁,我们要访问的frame还没建好,所以playwright维护frame列表还没有新页面。
而page.on监听framenavigated是异步的,所以通过page.on的handler等待返回进行显式等待frame更新完成的逻辑也行不通。
所以怎么获取新打开的iframe呢?显然还是监听事件,但只不过使用了wait_for_event方法:
点击菜单以后默认会加载首页的iframe,此时我们正在进行左侧菜单的点击操作,完成菜单进入后,iframe会被刷新/重建,此时,wait_for_event是在整个页面操作的,所以无论是修改原来iframe的地址、还是重建一个新的iframe,都能够被成功等待到。
一旦iframe完成跳转,说明iframe已经建好,frame ()方法就能获取到对应的frame,
然后,我们通过wait_for_load_state就可以等待iframe的DOM树创建完毕,然后就可以执行操作了(页面第一个iframe首页会早于下面的时机,所以不需要再加别的逻辑~)。
page2.wait_for_event("framenavigated")
page2.frame("xxxx").wait_for_load_state()
注意:
不要混淆frame_locator和frame
frame_locator是locator,frame是frame
一般我们针对元素操作,是通过frame来的,如果你只是用playwright的自带初级locator,当然framelocator也可以用于定位元素,不过功能上不太强大。