我遇到了chrome自动填充行为的几个形式的问题。

表单中的字段都有非常常见和准确的名称,例如“email”、“name”或“password”,并且它们还设置了autocomplete=“off”。

自动完成标志已经成功禁用了自动完成行为,当你开始输入时,会出现一个下拉的值,但没有改变Chrome自动填充字段的值。

这种行为是可以的,除了chrome填充输入不正确,例如填充电话输入与电子邮件地址。客户抱怨过这个问题,所以它被证实在很多情况下都发生了,而不是我在我的机器上本地操作的某种结果。

目前我能想到的唯一解决方案是动态生成自定义输入名称,然后在后端提取值,但这似乎是一种相当笨拙的解决这个问题的方法。是否有任何标签或怪癖,改变自动填充行为,可以用来解决这个问题?


当前回答

Finally I think I came with a decent solution. Understanding better how the dropdown works with Chrome helped :) Basically, the dropdown will be displayed when you focus the input and when you generate a mouse down event when you are typing an entry which matches with what Chrome has in memory. Keeping that in mind, and that Chrome does it for certain inputs when they have default names like "name", "email", etc. then we just need to remove the name when the dropdown is going to be displayed and add it back after :) I wanted to use a solution which can make it work just by adding the attribute autocomplete off. I thought it made sense. This is the code:

解决方案1

jQuery('body').on('mousedown','[name="name"][autocomplete="off"], [name="email"][autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    if(typeof this.currentName =="undefined")
        this.currentName=jQuery(this).attr('name');
    jQuery(this).attr('name','');
});

jQuery('body').on('blur','[autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    jQuery(this).attr('name',this.currentName);
});

解决方案2(我最喜欢的一个)

The solution I described above will remove the name of the input until we remove the focus (blur), in that moment it will put the original name back. But might happen that we are interested on having access to the input through its name attribute while we are typing. Which means that we need to put the name back right after each input. This solution, basically is based on the first solution. In this case, we will add the name on key down, and put it back on keyup. I think this is more neat for compatibility with what the "autocomplete off" behaviour should be. Anyway this is the code:

jQuery('body').on('mousedown keydown','[name="name"][autocomplete="off"], [name="email"][autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    if(typeof this.currentName =="undefined")
        this.currentName=jQuery(this).attr('name');
    jQuery(this).attr('name','');
});
jQuery('body').on('blur keyup','[autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    if(typeof this.currentName !="undefined")
        jQuery(this).attr('name',this.currentName);
});

请注意,对于解决方案1和2,我只采用输入名称为“name”和“email”的情况。对于任何其他情况下,这个属性使Chrome生成下拉,你将不得不添加它在选择器的鼠标下拉事件。

解决方案3

这个解决方案要复杂得多。我没有意识到我们试图纠正的行为只是基于那些带有特定名称的输入,如“姓名,电子邮件等”。这种解决方案的方法是在这种情况下,Chrome显示的其他名称,我们不知道一个先验。这将是一个非常通用的解决方案。我不像其他两个那样喜欢,主要是因为当我们按下删除键时,可能会有一个小闪烁。我会在下面解释。

我发现,下拉框出现在第二次点击输入后,而不是第一次点击时,当你第一次聚焦在输入上时。我为所有这些元素绑定了一个“mousedown”事件,其中处理程序基本上检测它是否已经聚焦在输入上,如果它检测到另一个“鼠标向下”,强制一个.blur(),然后是.focus(),防止第二次点击时的下拉。我希望,这是清楚的,以防万一,这是我使用的代码:

jQuery('body').on('mousedown','[autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    if(jQuery(this).is(':focus')) {
        jQuery(this).blur();
        jQuery(this).focus();
    }
});

In the other hand, in order to prevent the dropdown while you are typing in case it matches with Chrome suggestions... This is a little bit tricky. I just decided to replace the default behaviour of an input while user types. The dropdown evaluates the input on mouse down, so I prevent the default behaviour for alphanumerics, space, etc. The only problem is with Command,Ctrl and delete. For this case I had to bind also an event on mouse up. It allows the default behaviour in the first two cases so you can make copy, and paste, or select all. In the case of the delete, I have to allow the default behaviour, but if after deleting a character the input matches with Chrome suggestions, then again it was showing the dropdown. For this case I had to use the same trick of blur and focus. The only inconvenience I found on this is that since we are cancelling the behaviour on keyup, and chrome tries to show it on keydown, there is a small flicker. Anyway, this is the best I could do. Probably it will require for filtering of characters at one point. I just added the conditions made more sense for now. This is the second part of the code:

jQuery('body').on('keydown','[autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    var ctrlKey = 17,cmKey = 91;
    var charCode = e.which || e.keyCode;

    if(charCode!=16 && this.commandDown != true && this.ctrlDown != true && ((charCode>47 && charCode<58)||(charCode>64 && charCode<91)||(charCode>96 && charCode<123)||charCode==0 || charCode==32)){ 
        e.preventDefault();
        var charStr = String.fromCharCode(charCode);
        if(!e.shiftKey)
            charStr = charStr.toLowerCase(charStr);
        $(this).val($(this).val() + charStr);
    }else{
        if (charCode == cmKey) this.commandDown = true;
        if (charCode == ctrlKey) this.ctrlDown = true;
    }
});
jQuery('body').on('keyup','[autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    var allowed=[8];//Delete
    var ctrlKey = 17,cmKey = 91;
    var charCode = e.which || e.keyCode;

    if (charCode == cmKey) {this.commandDown = false};
    if (charCode == ctrlKey) {this.ctrlDown = false};
    if(allowed.indexOf(charCode)>=0 || (this.commandDown!=false && this.ctrlDown!=false)){
        jQuery(this).blur();
        jQuery(this).focus();
}

就像我说过的,这个解要复杂得多。这是我使用的第一个,直到我意识到下拉列表只出现在某些输入名称上。

抱歉写了这么多,我只是想确保一切都清楚。我希望这能有所帮助。

其他回答

1月20日chrome更新

上面的解决方案都不起作用,包括添加假字段或设置autocomplete=new-password。是的,这些chrome浏览器不会自动完成,但当你输入密码字段时,它会再次建议密码。

我发现,如果你删除密码字段,然后添加它再次没有id,然后chrome不会自动填充它,也不建议输入密码。

使用类来获取密码值而不是id。

对于firefox来说,仍然需要添加一个虚拟元素。

这个解决方案还允许/禁止基于标志的自动补全:

html:

<!-- form is initially hidden, password field has a dummy id and a class 'id' -->
<form id="loginForm" style="display:none;">
   <span>email:</span><input type="text" placeholder="Email" id="loginEmailInputID"/>
   <span>Password:</span><input class="loginPasswordInput" type="password" placeholder="Password" id="justForAutocomplete"/>
</form>

页面加载:

function hideAutoComplete(formId) {
    let passwordElem=$('#'+formId+' input:password'), prev=passwordElem.prev();
    passwordElem.remove();
    prev.after($('<input type="password" style="display:none">'), passwordElem.clone().val('').removeAttr('id'));
}

if (!allowAutoComplete) hideAutoComplete('loginForm');
$('#loginForm').show();

当你需要密码时:

$('.loginPasswordInput').val();

我的工作,因为上面没有一个似乎工作在Chrome 63及以上

我在我的网站上通过替换违规的输入元素来解决这个问题

<p class="input" contenteditable="true">&nbsp;</p>

在提交之前使用jQuery填充隐藏字段。

但这确实是一个可怕的黑客,因为铬的一个糟糕的决定。

在Chromium 53.0.2785.92(64位)上,以下工作

<div style="visibility:hidden">
    <input type="text" name="fake_username_remembered">
    <input type="password" name="fake_password_remembered">
</div>

显示:none不工作

没有一个解决方案对我有效。最后,在花了好几个小时后,我想出了这个ReactJS的解决方案。

在FireFox 54.0.1, Chrome 61.0.3163.100, Mac OS 10.13上测试

我保持类型=“文本”,并将其更改为onChange事件上的相关类型。

例: HTML:

<输入类型=“文本”占位符=“电子邮件”/>

JS:

setAttr2: function(e){
    var value = e.target.value;
    if(value.length){
      e.target.setAttribute('type', 'email')
    } else {
      e.target.setAttribute('type', 'text')
    }
  }

对我来说很简单

<form autocomplete="off" role="presentation">

做到了。

在多个版本上进行了测试,最后一次尝试是在56.0.2924.87