V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
cy97cool
V2EX  ›  JavaScript

tampermonkey 如何自动填充密码 并通过前端的表单检查

  •  
  •   cy97cool · 2020-08-27 00:11:26 +08:00 · 3201 次点击
    这是一个创建于 1550 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求:类似 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 库的

    第 1 条附言  ·  2020-08-27 17:58:44 +08:00

    4L解决了这个问题, 感谢CoolSpring大佬

    解决方案写到了我的blog里,欢迎顺手访问一下: https://blog.chenyuan.me/JavaScript/#tampermonkey

    • Tampermonkey自动填充用户名密码表单,并通过前端的表单检查
    • 使用browserify将npm包打包成浏览器能用的js文件
    11 条回复    2020-11-23 17:48:45 +08:00
    iNaru
        1
    iNaru  
       2020-08-27 00:57:39 +08:00   ❤️ 1
    input.dispatchEvent(new Event('input', { bubbles: true }));
    cy97cool
        2
    cy97cool  
    OP
       2020-08-27 07:31:55 +08:00
    @iNaru 没有用呢 仍然要求“请输入用户名!”
    initEvent 的第二个参数就是 bubbles
    cy97cool
        3
    cy97cool  
    OP
       2020-08-27 07:38:14 +08:00
    https://ant.design/components/form-cn/
    找到一个可以用来验证的例子,这个页面中的 嵌套结构与校验信息 部分,Username 右边有个 Need Help?的链接

    对这个 input 右键 检查元素,在 Console 里输入 $0.value="1" , 然后点击这个表单的 Submit,会报错“Username is required”。

    问题就是:在 Console 里输入啥神奇的代码,能成功通过这个表单的检查
    CoolSpring
        4
    CoolSpring  
       2020-08-27 09:53:31 +08:00   ❤️ 2
    如果是 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);
    cy97cool
        5
    cy97cool  
    OP
       2020-08-27 10:07:57 +08:00
    @CoolSpring 感谢 确实有用
    Damon3621
        6
    Damon3621  
       2020-10-20 14:06:05 +08:00
    Hi 兄弟 请问你如何获取页面中的 input 框呢?我最近也在写自动填充插件,遇到问题了。 比如腾讯视频 他的 Input 框放在 iframe 框架里,调用的话不是会跨域吗
    cy97cool
        7
    cy97cool  
    OP
       2020-10-21 10:21:20 +08:00
    @Damon3621 如果这个 iframe 是有 url 的,你可以对这个 iframe 的 url 启用脚本
    Damon3621
        8
    Damon3621  
       2020-10-21 14:11:29 +08:00
    @cy97cool 大佬,可以说的具体点嘛 我现在能获取这个 iframe 的 url 但不能操作里面的 dom 怎么对这个 url 启用脚本呢
    cy97cool
        9
    cy97cool  
    OP
       2020-10-30 20:00:38 +08:00
    @Damon3621 不要局限你的思维啊 你以为只能在外层的网页匹配脚本运行嘛?
    举个例子 如果我写一个脚本 匹配所有网站 那你打开当前这个窗口的时候会显示几次呢?
    // @match https://*/*
    console.log("script started")

    你的脚本可以去匹配 iframe 的 url 而不是匹配地址栏的 url
    Damon3621
        10
    Damon3621  
       2020-11-03 14:18:36 +08:00
    @cy97cool 非常感谢 确实有用
    Jonatvtwoex
        11
    Jonatvtwoex  
       2020-11-23 17:48:45 +08:00
    原因是校验逻辑依赖 input 事件, 而 inputEle.value = xxx 并不会触发 input 事件

    const inputEle = document.querySelector(`input[name=${key}]`)
    inputEle.value = fields[key]
    // 关键代码: input 元素在事后触发一下 input 事件
    inputEle.dispatchEvent(new Event('input'));
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2731 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 11:13 · PVG 19:13 · LAX 03:13 · JFK 06:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.