需求:类似 LastPass 这种可以自动填充用户名密码,点击提交
难点:很多现代化的页面前端做了表单校验,直接赋值 input 的 value 不能通过表单校验
关键在于没能触发人家框架的 event listener
查资料咯,发现了这个解答 https://stackoverflow.com/a/35807417
就是触发 input 、keyup 、change 事件,但实际测试仍然不行,甚至我把在开发人员工具能看到的 event listner 全触发了一边都没用 sad
function fireChangeEvents(element){
var changeEvent = null;
for(var i of ["keypress","focus", "input", "keydown", "keyup", "change", "blur", "click", "invalid", "mouseover", "popstate", "reset", "scroll", "selectionchange", "submit", "transitionend"]){
changeEvent = document.createEvent ("HTMLEvents");
changeEvent.initEvent (i, true, true);
element.dispatchEvent (changeEvent);
}
}
fireChangeEvents(document.querySelectorAll("input")[0])
然后接着找,发现一个能模拟用户交互的 npm 包: https://github.com/testing-library/user-event
然后折腾了一下 browserify 打包成浏览器可以用的 js 文件,实际测试可行:
userEvent.type(document.querySelectorAll("input")[0], USERNAME);
userEvent.type(document.querySelectorAll("input")[1], PASSWORD);
问题是解决了,但觉得为了一个触发 event 引入一个 500KB 的 js 文件有点蠢( uglify 之后也有 300KB ),问问大佬们有没有更好的方案,不需要引入这么重的 js 库的
input.dispatchEvent(new Event('input', { bubbles: true }));
没有用呢 仍然要求“请输入用户名!”
initEvent 的第二个参数就是 bubbles
https://ant.design/components/form-cn/
找到一个可以用来验证的例子,这个页面中的 嵌套结构与校验信息 部分,Username 右边有个 Need Help?的链接
对这个 input 右键 检查元素,在 Console 里输入 $0.value="1" , 然后点击这个表单的 Submit,会报错“Username is required”。
问题就是:在 Console 里输入啥神奇的代码,能成功通过这个表单的检查
如果是 React,似乎可以用这个: https://stackoverflow.com/questions/23892547/what-is-the-best-way-to-trigger-onchange-event-in-react-js
var input = document.getElementById("complex-form_username");
var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(input, 'react 16 value');
var ev2 = new Event('input', { bubbles: true});
input.dispatchEvent(ev2);
感谢 确实有用
Hi 兄弟 请问你如何获取页面中的 input 框呢?我最近也在写自动填充插件,遇到问题了。 比如腾讯视频 他的 Input 框放在 iframe 框架里,调用的话不是会跨域吗
如果这个 iframe 是有 url 的,你可以对这个 iframe 的 url 启用脚本
大佬,可以说的具体点嘛 我现在能获取这个 iframe 的 url 但不能操作里面的 dom 怎么对这个 url 启用脚本呢
不要局限你的思维啊 你以为只能在外层的网页匹配脚本运行嘛?
举个例子 如果我写一个脚本 匹配所有网站 那你打开当前这个窗口的时候会显示几次呢?
// https://*/*
console.log("script started")
你的脚本可以去匹配 iframe 的 url 而不是匹配地址栏的 url
非常感谢 确实有用
原因是校验逻辑依赖 input 事件, 而 inputEle.value = xxx 并不会触发 input 事件
const inputEle = document.querySelector(`input[name=${key}]`)
inputEle.value = fields[key]
// 关键代码: input 元素在事后触发一下 input 事件
inputEle.dispatchEvent(new Event('input'));