【问题标题】:Autofill does not trigger onChange自动填充不会触发 onChange
【发布时间】:2019-08-10 04:36:57
【问题描述】:

我有一个登录表单,当页面打开时,Chrome 会自动填写凭据。但是,input 元素的onChange 事件没有被触发。

单击页面上的任意位置会使它们注册到inputvalue 属性中,这正是我们所需要的。我试过event.target.click(),但没有帮助。

在 onChange 中,我将值设置为如下状态:

this.setState({ email: event.target.value })

如果email.length === 0,提交按钮将被禁用。

因此,即使页面显示已填写凭据,提交按钮仍然看起来处于禁用状态。

由于单击任何地方都会注册值,因此单击提交按钮也会在提交前注册它们。所以它完美地工作。

但这与时间无关,字段永远不会被填充。当我打开开发者控制台并检查时,值字段为空,直到我单击某处。

这里唯一的问题是该按钮看起来已禁用,因为在单击某些内容之前,电子邮件输入值是空的。有没有一个hacky解决方案?

【问题讨论】:

  • 你能发布一个指向 jsfiddle 的链接吗?那会很有帮助。
  • 如果您禁用基本功能,您还必须在启动时检查是否启用它。因此,在浏览器完全加载所有数据后,将“if email.length”检查放在某处,以便您检测到输入是自动填充的。基本超时可以工作。
  • 它永远不会被填充。当我打开开发者控制台并检查时,值字段为空,直到我单击某处。
  • 你解决过这个问题吗?我有同样的问题。页面加载并且输入(电子邮件地址)已填充,但输入 ref 的值是空的,直到与页面交互(单击即可),所以第二次渲染就可以了。我应该提到这仅在 Chrome 中; Firefox 工作正常。
  • 如果能提供一些代码就更好了

标签: javascript html reactjs dom autofill


【解决方案1】:

如果通过自动填充在表单中填写数据,并且您尝试直接提交表单,则像 firefox 这样的浏览器不会获取输入数据,因为它不处于该输入的状态。

但如果您使用的是基于类的组件,我们可以在 useEffect 钩子或 componentDidMount 中解决它。

useEffect(() => {

 setUserName(document.getElementById('username').value);

}, [])

setUserName 这里是状态设置方法,替换成你的。 使用您输入字段的 ID 更改用户名。

【讨论】:

    【解决方案2】:

    使用 oninput 代替 onchange 可以解决问题

    【讨论】:

    • 不知道为什么这不是最佳答案!
    • 因为它不是 OP 问题的答案。 oninput(就像 onchange 一样)仅在用户交互后触发。这是 OP 的问题,使用 oninput 无法解决。
    • 它不起作用
    【解决方案3】:

    我偶然发现了这个问题,因为我遇到了同样的问题。不在 React 中,但问题是普遍存在的。也许这会帮助其他偶然发现这一点的人。

    其他答案都没有真正回答这个问题。 OP 描述的问题是 Chrome 不会设置输入的值直到用户与页面交互。这可以是点击页面,甚至可以在控制台中输入随机内容。

    在用户交互发生后,输入的值被设置并触发更改事件。

    您甚至可以直观地看到这一点,因为自动填充文本的样式在首次呈现时会有所不同,并且在交互发生后会更改输入的样式。

    另外:触发点击或设置焦点或任何代码都无济于事,只有真正的人类交互。

    所以轮询值不是解决方案,因为如果页面没有被点击,值将保持为空。还声明您不能依赖更改事件并不真正相关,因为事件 在延迟设置值时正确触发。问题在于无限期延迟。

    但是,您可以轮询 Chrome 的伪 CSS 类是否存在。在 Chrome 83(2020 年 6 月)中,它们是 :-internal-autofill-selected:-internal-autofill-previewed。但是,这些确实会定期更改。此外,它们在渲染后不会直接存在。所以你应该设置一个足够的超时时间,或者轮询它。

    原生 JavaScript 中的草率示例:

    var input = document.getElementById('#someinput');
    
    setTimeout(() => {
       if (input.matches(':-internal-autofill-selected')) {
          /* do something */
       }
    }, 500);
    

    此时您仍然无法获取值,因此在这方面它仍然无法解决问题,但至少您可以根据自动填充数据的存在启用提交按钮(正如 OP 想要的那样做)。或者做一些其他的视觉效果。

    【讨论】:

    • Cyber​​ Valdez 说的怎么样,使用 oninput!立即为我工作。
    • @JessePepper 不,oninput 的行为与 onchange (目前在 Chrome 90 上测试)相同,因为它仅在用户交互后触发(OP 的问题)。我的答案仍然是解决此问题并为 OP 问题提供某种解决方案的唯一答案。你能恢复不被要求的否决票吗?谢谢。
    • 我喜欢卡里姆的这个回答。我会指出,如果您有不同/竞争的“自动填充”行为,请小心。当谷歌浏览器自动填充工作时,我得到了“字体切换”/等待用户点击,如 Karim 所述。 (i.stack.imgur.com/uvwqs.gif) LastPass 扩展自动填充工作时;我得到了正确的字体和 valueChange 事件。 (i.stack.imgur.com/D3QhJ.gif)
    • 另外,让我们记住autofill vs autocomplete之间的区别;正如卡里姆所说,这个问题是关于 autofill (自动完成意味着一些用户交互)。最后,正如 Karim 指出的那样,CSS 伪类可能会改变;在 2017 年似乎有人 query for CSS pseudoclass :-webkit-autofill(但现在请参阅 Karim 对 :-internal-autofill-selected 的使用)
    • 还有一点,正如 Karim 所说,即使您轮询/监视 CSS 伪类,这 并不意味着输入具有价值(即使输入 似乎有一个值);卡里姆说“你仍然无法获得价值......所以它仍然不能解决问题”。这对我来说是正确的——我的应用程序需要输入值来进行查找。所以我别无选择只能等待用户在页面上点击。我无法成功地使用autocomplete="off" 来击败自动填充,除非我对[type="search"](stackoverflow.com/a/30873633/1175496) 有攻击性(同时用于用户名密码)
    【解决方案4】:

    答案是在表单中使用 autocomplete="off" 禁用表单的自动完成功能,或者定期轮询以查看其是否已填满。

    问题在于不同浏览器对自动填充的处理方式不同。 有些发送更改事件,有些则不发送。所以几乎不可能 挂钩在浏览器自动完成时触发的事件 输入字段。

    • 改变不同浏览器的事件触发器:

      • 对于用户名/密码字段:

        1. Firefox 4、IE 7 和 IE 8 不调度更改事件。
        2. Safari 5 和 Chrome 9 会调度 change 事件。
      • 对于其他表单域:

        1. IE 7 和 IE 8 不调度更改事件。
        2. 当用户从建议列表中选择一个值并从字段中跳出标签时,Firefox 4 会调度 change change 事件。
        3. Chrome 9 不会调度更改事件。
        4. Safari 5 确实调度了 change 事件。

    您最好的选择是禁用表单的自动完成功能 autocomplete="off" 在您的表单中或定期轮询以查看 如果已满。

    关于是否填写在 document.ready 之前或之前的问题 再次,它因浏览器而异,甚至因版本而异。 仅当您选择用户名密码时,才适用于用户名/密码字段 字段已填写。所以总的来说,如果你有一个非常混乱的代码 尝试附加到任何事件。

    你可以好好阅读一下 HERE

    看看这个帖子:Detecting Browser Autofill

    【讨论】:

    • 无法访问良好阅读链接
    【解决方案5】:

    event.target.click() 将“模拟”单击并触发 onClick() 事件,但不像浏览器窗口中的物理单击。

    您是否已经尝试过使用 focus() 代替(或附加于)click()?您可以尝试将焦点放在输入元素上,然后检查是否设置了该值。如果可行,您可以在焦点和点击时添加 this.setState({ email: event.target.value })

    【讨论】:

      【解决方案6】:

      不需要触发点击事件,我觉得如果像这样在componentDidMount中设置email状态会更好

      this.setState({ email: document.getElementById('email').value })
      

      因此,一旦componentDidMount() 被调用,您将获得由 Chrome 填写的电子邮件并更新 state,然后呈现提交按钮并使其启用。

      您可以在 link 上阅读有关 React 生命周期的更多信息

      【讨论】:

      • 听起来问题是在渲染后发生的,所以检查 componentDidMount 可能没有什么不同。希望 OP 能够参与进来,让我们更加清楚。
      • useEffect 内设置调试器,电子邮件输入的.value 为空,并且在Chrome 填充输入后useEffect 不会再次触发(省略数组参数)。直到我与页面交互(导致渲染),useEffect 才第二次触发,并且可以检测到由 Chrome 放在那里的电子邮件字段中的值。
      【解决方案7】:

      我在这里创建了一个示例应用程序 https://codesandbox.io/s/ynkvmv16v

      这能解决您的问题吗?

      【讨论】:

      • 否,因为e.target.value 始终为空。这就是问题所在。
      • 您是否尝试记录事件值?您上面的代码 sn-p 是非常错误的。 event.target.email 应该是 event.target.value。另外,您能告诉我您遇到此问题的浏览器版本吗?
      • 更正了那个错字。 Chrome macOS 73.0.3683.75
      • 记录哪个事件值? onChange 没有被触发,所以没有事件。
      • 我使用的是同一版本的 chrome,但没有发现问题。你介意通过codesandbox.io分享你的代码吗?
      猜你喜欢
      • 2016-01-15
      • 2021-12-06
      • 2012-06-12
      • 2012-04-17
      • 1970-01-01
      • 2015-11-24
      • 2014-03-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多