编写Tampermonkey用户脚本模拟点击React管理的按钮问题
解决Quillbot总结页“Paste Text”按钮模拟点击问题
直接调用div.click()没效果,是因为React用的是合成事件系统,原生的click()方法只会触发浏览器的原生点击事件,但不会触发React绑定的合成事件监听。下面给你两种可行的解决方案,都是基于原生JS的Tampermonkey脚本实现:
方法一:模拟完整的鼠标事件流程
React的合成事件需要完整的mousedown -> mouseup -> click事件链才能触发,我们可以手动构造并分发这些事件:
// ==UserScript== // @name Quillbot 自动点击粘贴文本按钮 // @namespace http://tampermonkey.net/ // @version 0.1 // @description 在Quillbot总结页自动触发Paste Text按钮点击 // @match https://quillbot.com/summarize // @grant none // ==/UserScript== (function() { 'use strict'; // 等待目标元素加载完成(React页面元素不是一次性渲染的) function waitForElement(selector, timeout = 10000) { return new Promise((resolve, reject) => { const checkInterval = setInterval(() => { const target = document.querySelector(selector); if (target) { clearInterval(checkInterval); resolve(target); } }, 500); setTimeout(() => { clearInterval(checkInterval); reject(new Error('超时未找到目标按钮')); }, timeout); }); } // 模拟完整的鼠标点击流程,触发React合成事件 function triggerFullClick(element) { // 依次触发mousedown、mouseup、click事件 ['mousedown', 'mouseup', 'click'].forEach(eventType => { const event = new MouseEvent(eventType, { bubbles: true, cancelable: true, view: window }); element.dispatchEvent(event); }); } // 主执行逻辑 waitForElement('div[aria-label="Paste Text"]') // 替换成你找到的按钮选择器 .then(btn => { triggerFullClick(btn); console.log('粘贴按钮已触发'); }) .catch(err => console.error(err.message)); })();
注意事项:
- 选择器需要根据实际页面元素调整:打开浏览器F12开发者工具,找到“Paste Text”对应的div元素,复制它的CSS选择器(比如带特定class、aria-label属性的选择器),替换代码里的
div[aria-label="Paste Text"]。 - 这个方法兼容性强,不受React版本影响。
方法二:直接调用React元素的onClick回调
如果能拿到React元素绑定的onClick函数,直接调用它更高效:
// ==UserScript== // @name Quillbot 自动点击粘贴文本按钮 // @namespace http://tampermonkey.net/ // @version 0.1 // @description 在Quillbot总结页自动触发Paste Text按钮点击 // @match https://quillbot.com/summarize // @grant none // ==/UserScript== (function() { 'use strict'; function waitForElement(selector, timeout = 10000) { return new Promise((resolve, reject) => { const checkInterval = setInterval(() => { const target = document.querySelector(selector); if (target) { clearInterval(checkInterval); resolve(target); } }, 500); setTimeout(() => { clearInterval(checkInterval); reject(new Error('超时未找到目标按钮')); }, timeout); }); } // 获取React元素的props对象 function getReactProps(element) { // React会给DOM元素添加带__reactFiber$前缀的属性,不同版本可能略有差异 const fiberKey = Object.keys(element).find(key => key.startsWith('__reactFiber$')); if (!fiberKey) return null; const fiber = element[fiberKey]; // 从fiber节点中找到对应的props return fiber?.return?.props; } waitForElement('div[aria-label="Paste Text"]') .then(btn => { const props = getReactProps(btn); if (props?.onClick) { props.onClick(); console.log('直接调用React onClick成功'); } else { // fallback到方法一 ['mousedown', 'mouseup', 'click'].forEach(eventType => { const event = new MouseEvent(eventType, { bubbles: true, cancelable: true, view: window }); btn.dispatchEvent(event); }); } }) .catch(err => console.error(err.message)); })();
注意事项:
- 这个方法依赖React内部的fiber节点结构,不同React版本可能会有属性名变化,如果失效,直接用方法一即可。
内容的提问来源于stack exchange,提问作者Nvl
相关产品推荐
相关产品推荐

