对于那些寻求快速答案的人,这里是主要代码:
await Promise.all([page.waitForNavigation(), el.click()])
...其中el
是指向SPA中另一页的链接,click
可以是任何导致导航的事件。详情请见下文。
我认为如果您不能依赖页面内容,waitFor
并不是很有用。即使您可以,在大多数情况下,这似乎比自然地对导航做出反应更不可取。幸运的是,page.waitForNavigation
适用于单页应用程序。以下是使用链接上的单击事件(表单提交应该也适用)在微型原生SPA模拟中导航到页面之间的最小完整示例,它使用history API(下面的index.html
)。我使用了Node 10和Puppeteer 5.4.1。
index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<script>
const nav = `<a href="/">Home</a> | <a href="/about">About</a> |
<a href="/contact">Contact</a>`;
const routes = {
"/": `<h1>Home</h1>${nav}<p>Welcome home!</p>`,
"/about": `<h1>About</h1>${nav}<p>This is a tiny SPA</p>`,
};
const render = path => {
document.body.innerHTML = routes[path] || `<h1>404</h1>${nav}`;
document.querySelectorAll('[href^="/"]').forEach(el =>
el.addEventListener("click", evt => {
evt.preventDefault();
const {pathname: path} = new URL(evt.target.href);
window.history.pushState({path}, path, path);
render(path);
})
);
};
window.addEventListener("popstate", e =>
render(new URL(window.location.href).pathname)
);
render("/");
</script>
</body>
</html>
index.js
:
const puppeteer = require("puppeteer");
let browser;
(async () => {
browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto("http://localhost:8000");
console.log(page.url());
console.log(await page.$eval("p", el => el.innerHTML));
const [el] = await page.$x('//a[text()="About"]');
await Promise.all([page.waitForNavigation(), el.click()]);
console.log(page.url());
console.log(await page.$eval("p", el => el.innerHTML));
})()
.catch(err => console.error(err))
.finally(async () => await browser.close())
;
示例运行:
$ python3 -m http.server &
$ node index.js
http://localhost:8000/
Welcome home!
http://localhost:8000/about
This is a tiny SPA
如果
await Promise.all([page.waitForNavigation(), el.click()]);
这种模式看起来很奇怪,请参考
此问题讨论串,其中解释了直觉上存在的
陷阱。
await page.waitForNavigation();
await el.click();
导致竞态条件。
与上面所示的
Promise.all
相同的事情可以通过以下方式完成:
const navPromise = page.waitForNavigation({timeout: 1000});
await el.click();
await navPromise;
查看此相关答案以获取更多关于使用Puppeteer导航单页应用程序的信息,包括哈希路由。