123 lines
3.5 KiB
JavaScript
123 lines
3.5 KiB
JavaScript
const BaseAction = require('../core/base-action');
|
|
const SmartSelector = require('../core/smart-selector');
|
|
|
|
/**
|
|
* 点击动作
|
|
*/
|
|
class ClickAction extends BaseAction {
|
|
async execute() {
|
|
const selector = this.config.selector || this.config.find;
|
|
|
|
if (!selector) {
|
|
throw new Error('缺少选择器配置');
|
|
}
|
|
|
|
this.log('info', '执行点击');
|
|
|
|
// 查找元素
|
|
const smartSelector = SmartSelector.fromConfig(selector, this.page);
|
|
const element = await smartSelector.find(this.config.timeout || 10000);
|
|
|
|
if (!element) {
|
|
throw new Error(`无法找到元素: ${JSON.stringify(selector)}`);
|
|
}
|
|
|
|
// 滚动到可视区域
|
|
await element.evaluate((el) => {
|
|
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
});
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 300));
|
|
|
|
// 点击
|
|
await element.click();
|
|
|
|
this.log('debug', '✓ 点击完成');
|
|
|
|
// 验证点击后的变化(新元素出现 / 旧元素消失)
|
|
if (this.config.verifyAfter) {
|
|
await this.verifyAfterClick(this.config.verifyAfter);
|
|
}
|
|
|
|
// 等待页面变化(如果配置了)
|
|
if (this.config.waitForPageChange) {
|
|
await this.waitForPageChange(this.config.checkSelector);
|
|
}
|
|
|
|
// 可选的等待时间
|
|
if (this.config.waitAfter) {
|
|
await new Promise(resolve => setTimeout(resolve, this.config.waitAfter));
|
|
}
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* 验证点击后的变化
|
|
*/
|
|
async verifyAfterClick(config) {
|
|
const { appears, disappears, timeout = 10000 } = config;
|
|
|
|
// 验证新元素出现
|
|
if (appears) {
|
|
this.log('debug', '验证新元素出现...');
|
|
for (const selector of (Array.isArray(appears) ? appears : [appears])) {
|
|
try {
|
|
await this.page.waitForSelector(selector, { timeout, visible: true });
|
|
this.log('debug', `✓ 新元素已出现: ${selector}`);
|
|
} catch (error) {
|
|
throw new Error(`点击后验证失败: 元素 "${selector}" 未出现`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 验证旧元素消失
|
|
if (disappears) {
|
|
this.log('debug', '验证旧元素消失...');
|
|
for (const selector of (Array.isArray(disappears) ? disappears : [disappears])) {
|
|
try {
|
|
await this.page.waitForSelector(selector, { timeout, hidden: true });
|
|
this.log('debug', `✓ 旧元素已消失: ${selector}`);
|
|
} catch (error) {
|
|
throw new Error(`点击后验证失败: 元素 "${selector}" 未消失`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 等待页面内容变化
|
|
*/
|
|
async waitForPageChange(checkSelector, timeout = 15000) {
|
|
this.log('debug', '等待页面变化...');
|
|
|
|
const startTime = Date.now();
|
|
const initialUrl = this.page.url();
|
|
|
|
while (Date.now() - startTime < timeout) {
|
|
// 检查 URL 是否变化
|
|
if (this.page.url() !== initialUrl) {
|
|
this.log('debug', '✓ URL 已变化');
|
|
return true;
|
|
}
|
|
|
|
// 检查特定元素是否出现
|
|
if (checkSelector) {
|
|
const smartSelector = SmartSelector.fromConfig(checkSelector, this.page);
|
|
const newElement = await smartSelector.find(1000);
|
|
if (newElement) {
|
|
this.log('debug', '✓ 页面内容已变化');
|
|
return true;
|
|
}
|
|
}
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
}
|
|
|
|
this.log('warn', '等待页面变化超时');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
module.exports = ClickAction;
|