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

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

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

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

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


当前回答

在chrome浏览器中,如果你用标签包围一个输入,在标签内加上街道、地址或两者都写上,它会忽略任何试图禁用自动填充的尝试。

<label for="searchAddress" class="control-label"> Street Address <input type="text" class="form-control" name="searchAddress></label>

Chrome通过检测标签中的关键字来判断输入类型。它可能对其他关键字也是如此。

其他回答

你必须添加这个属性:

autocomplete="new-password"

来源链接:全文

我遇到了“现在登录或注册”模式窗口的问题,如果用户已经将他们的凭据保存到浏览器中,这是一个问题。sign in和register字段都被填充了,所以我可以用下面的angular js指令来清除它们:

(function () { "use strict"; var directive = function ($timeout) { return { restrict: "A", link: function (scope, element, attrs) { $timeout(function () { element.val(" "); $timeout(function () { element.val(""); }); }); } }; }; angular.module("app.directives").directive("autofillClear", ["$timeout", directive]); }());

它基本上与之前使用jquery的一些答案相同,但以一种角度的方式完成。

我的解决方案取决于三件事:

keydown事件 屏蔽字段名 在提交时删除字段值

首先,我们需要防止用户名和密码都自动补全,因此,最初我们将设置两个标志,i ->用户名和j ->密码为真值,因此如果没有任何keydown字段,i和j都将为真。

在可能的情况下,字段屏蔽发生在服务器端,通过传递随机字符串,它也可以很容易地使用客户端。

这是代码:

$(document).ready(function(){
   i= true; //username flag
   j= true; // password flag
   $("#username{{$rand}}").keydown(function(e){
          // {{$rand}} is server side value passed in blade view
          // keyboard buttons are clicked in the field
            i = false;       
    });
   $("#passowrd{{$rand}}").keydown(function(e){
          // {{$rand}} is server side value passed in blade view
          // keyboard buttons are clicked in the field
            j = false;       
    });
    // Now we will use change event,
   $("#username{{$rand}}").change(function(){
    if($(this).val() != ''){ //the field has value
        if(i){ // there is no keyboard buttons clicked over it
            $(this).val(''); // blank the field value
        }

    }
})
$("#password{{$rand}}").change(function(){
    if($(this).val() != ''){ // the same as username but using flag j
        if(j){
            $(this).val('');
        }

    }
})

   $("#sForm").submit(function(e){ // the id of my form
      $("#password-s").val($("#password{{$rand}}").val());
        $("#username-s").val($("#username{{$rand}}").val());
        // Here the server will deal with fields names `password` and `username` of the hidden fields
       $("#username{{$rand}}").val('');
        $("#password{{$rand}}").val(''); 

 })
})

下面是HTML:

<form class="form-horizontal" autocomplete="off" role="form" id="sForm" method="POST" action="https://example.com/login">

                        <input type="hidden" name="password" id="password-s">
                        <input type="hidden" name="username" id="username-s">

                            <label for="usernameTDU3m4d3I5" class="col-md-3 control-label" style="white-space: nowrap">Username</label>

                                <input id="usernameTDU3m4d3I5" placeholder="Username" autocomplete="off" style="border-bottom-left-radius: 10px; border-top-right-radius: 10px; font-family: fixed; font-size: x-large;" type="text" class="form-control" name="usernameTDU3m4d3I5" value="" required="required" autofocus="">                                

                            <label for="passwordTDU3m4d3I5" class="col-md-3 control-label" style="white-space: nowrap">Password</label>
                                <input id="passwordTDU3m4d3I5" placeholder="Password" autocomplete="off" type="password" class="form-control" name="pa-TDU3m4d3I5" required="">


                                <button type="submit" class="btn btn-success">
                                    <i class="fox-login" style="text-shadow: 0px 1px 0px #000"></i><strong>Login</strong>&nbsp;&nbsp;
                                </button>

                                </form>

上述解决方案确实不会消除或阻止用户名和密码的自动补全,但它使自动补全无用。也就是说,在没有敲击键盘按钮的情况下,字段值在提交之前将是空白的,因此用户将被要求输入它们。

更新

我们也可以,使用点击事件来防止自动完成用户列表出现在字段下面,如下所示:

 $("#username{{$rand}}").click(function(){

            $(this).val('');
            i = true;

})
$("#password{{$rand}}").click(function(){

            $(this).val('');
            j = true;

})

限制:

这种解决方案可能无法在触摸屏设备中正常工作。

最后的更新

我已经完成了如下干净的实现:

preventAutoComplete = true; // modifier to allow or disallow autocomplete
trackInputs = {password:"0", username:"0"}; //Password and username fields ids as object's property, and "0" as its their values
// Prevent autocomplete
    if(preventAutoComplete){
        $("input").change(function(e){ // Change event is fired as autocomplete occurred at the input field 
            trackId = $(this).attr('id'); //get the input field id to access the trackInputs object            
            if (trackInputs[trackId] == '0' || trackInputs[trackId] != $(this).val()){ //trackInputs property value not changed or the prperty value ever it it is not equals the input field value
                $(this).val(''); // empty the field
            }
        });
        $("input").keyup(function(e){
            trackId = $(this).attr('id');
            trackInputs[trackId] = $(this).val(); //Update trackInputs property with the value of the field with each keyup.
        });
    } 

我的黑客测试在Chrome 48:

由于Chrome试图找出字段的类型,它是通过查看诸如id或名称属性的<输入>,但也在相关的<标签>内容,你只需要找到这些无意义的名字。

对于id和名称,很容易选择这里没有列出的其他内容。

对于标签,我在中间插入了一个不可见的<span>,例如对于一个城市(它会打乱我的位置自动完成):

<span>Ci<span style="display:none">*</span>ty</span>

完整的工作示例:

<!DOCTYPE html> <html> <body> <form method="post" action="/register"> <div> <label for="name">Name</label> <input id="name" type="text" name="name" /> </div> <div> <label for="email">Email</label> <input id="email" type="text" name="email" /> </div> <div> <label for="id1">City</label> <input id="id1" type="text" name="id1" /> <-- STILL ON :( </div> <div> <label for="id2">Ci<span style="display:none">*</span>ty</label> <input id="id2" type="text" name="id2" /> <-- NOW OFF :) </div> </form> </body> </html>

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();
}

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

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