元素拾取跟随前台标签页: 点搜索等开新标签页后附着目标自动切换

- pickElement 轮询前经 /json/list 检查前台标签页, 变化时 activateTab 切换附着并重新注册/注入拾取脚本
- 结束时对所有已附着标签页清理拾取残留, 并移除全部 addScriptToEvaluateOnNewDocument 注入
This commit is contained in:
yu 2026-11-05 10:12:59 +08:00
parent 5250bf1e35
commit 91d998b2ea

View File

@ -1165,16 +1165,32 @@ export class BrowserSession implements BrowserLike {
}
const inject = () =>
this.evaluate(`(() => { try { delete window.__rpaPickResult; ${PICKER_BOOTSTRAP_SOURCE} } catch {} })()`);
const injectionIds: string[] = [];
const registerInjection = async () => {
const registered = await this.cdp<{ identifier?: string }>("Page.addScriptToEvaluateOnNewDocument", {
source: PICKER_BOOTSTRAP_SOURCE
}).catch(() => null);
if (registered?.identifier) injectionIds.push(registered.identifier);
};
// 跟随前台标签页:搜索/点按钮常开新标签页,附着目标切过去并重新注入,拾取不中断
const followForegroundTab = async () => {
if (this.win || !this.httpBase) return;
const pages = await listPageTargets(this.httpBase).catch(() => []);
const page = pages[0];
if (!page || page.id === this.activeTargetId) return;
await this.activateTab(page.id);
await this.cdp("Page.enable").catch(() => {});
await registerInjection();
await inject();
};
await this.cdp("Page.enable").catch(() => {});
const registered = await this.cdp<{ identifier?: string }>("Page.addScriptToEvaluateOnNewDocument", {
source: PICKER_BOOTSTRAP_SOURCE
}).catch(() => null);
const injectionId = registered?.identifier;
await registerInjection();
try {
await inject();
const deadline = Date.now() + Math.max(5000, timeoutMs);
while (Date.now() < deadline) {
await new Promise((resolve) => setTimeout(resolve, 400));
await followForegroundTab().catch(() => {});
const state = await this.evaluate<{ result: { ok: boolean; value?: ElementPickResult; reason?: string } | null; active: boolean }>(
"({ result: window.__rpaPickResult ?? null, active: window.__rpaPickerActive?.active === true })"
).catch(() => null);
@ -1187,11 +1203,14 @@ export class BrowserSession implements BrowserLike {
}
throw new RuntimeError("timeout", "拾取超时,请重新点击拾取");
} finally {
await this.evaluate(
"(() => { try { window.__rpaElementPicker?.cancelHard?.(); window.__rpaPickerActive = undefined; delete window.__rpaPickResult; } catch {} })()"
).catch(() => {});
if (injectionId) {
await this.cdp("Page.removeScriptToEvaluateOnNewDocument", { identifier: injectionId }).catch(() => {});
const cleanupExpr =
"(() => { try { window.__rpaElementPicker?.cancelHard?.(); window.__rpaPickerActive = undefined; delete window.__rpaPickResult; } catch {} })()";
await this.evaluate(cleanupExpr).catch(() => {});
for (const tabTransport of this.tabTransports.values()) {
await tabTransport.send("Runtime.evaluate", { expression: cleanupExpr }).catch(() => {});
}
for (const identifier of injectionIds) {
await this.cdp("Page.removeScriptToEvaluateOnNewDocument", { identifier }).catch(() => {});
}
}
}