Forms 2019年,Chrome 76,接近自动完成关闭

Forms 2019年,Chrome 76,接近自动完成关闭,forms,google-chrome,autocomplete,street-address,Forms,Google Chrome,Autocomplete,Street Address,关于这方面的帖子很少。你花了几个小时去检查每个答案,测试,阅读评论,发现没有解决方案。你在2019年做了什么,Chrome 76,可以用吗 autocomplete='nope' 这是Chrome 76当前的工作解决方案 更新,2020年1月:从Chrome 79开始,自动完成(如此处定义)似乎不再将Autocomplete=“一些未识别的值”视为等同于Autocomplete=“on”,因此Autocomplete=“nope”或类似功能现在可以有效地禁用自动完成和自动填充 更新,2020年

关于这方面的帖子很少。你花了几个小时去检查每个答案,测试,阅读评论,发现没有解决方案。你在2019年做了什么,Chrome 76,可以用吗

autocomplete='nope'

这是Chrome 76当前的工作解决方案

更新,2020年1月:从Chrome 79开始,自动完成(如此处定义)似乎不再将
Autocomplete=“一些未识别的值”
视为等同于
Autocomplete=“on”
,因此
Autocomplete=“nope”
或类似功能现在可以有效地禁用自动完成和自动填充

更新,2020年4月:他们再次更改了它。从Chrome 81开始,
autocomplete=“一些无法识别的值”
在禁用自动完成机制方面不再有效。然而,Autofill现在似乎比以前保守多了——它仍然不符合规范(带有
name=“email”
autocomplete=“off”
的字段仍然会收到自动填充建议),但它不会在随机表单字段上提供虚假的地址片段。因此,我现在的建议是使用
autocomplete=“off”
。如果您想在名为
email
的字段上执行此操作,您可能运气不好:-(


TL,DR:autocomplete属性似乎没有设置可以可靠地关闭所有autocomplete下拉列表。然而,导致这种情况的情况非常复杂,值得记录,希望能够清除大量相互冲突的建议

当前(76.0.3809.132)版本的Chrome中存在两种不同的机制,我们称之为自动填充和自动完成(不一定是它们的官方名称):

自动填充

自动填写功能尝试使用浏览器设置中存储的地址信息填写表单。它可以通过下拉列表底部的“管理地址…”选项(或类似选项)来识别。此功能不支持
autocomplete=“off”
autocomplete=“false”
,作为Chrome开发者的一项深思熟虑的决定

在年,zkoch提供了以下解决方法:

如果您确实想禁用自动填充,我们的建议如下: 这一点是利用autocomplete属性提供有效的, 字段的语义含义。如果遇到自动完成 我们无法识别的属性,我们不会尝试填充它

例如,如果CRM工具中有地址输入字段 如果你不想让Chrome自动填充,你可以赋予它语义 这意味着相对于你的要求是有意义的:例如。 autocomplete=“新用户街道地址”。如果Chrome遇到这种情况,它会 不会尝试自动填充该字段

这是尝试的解决方案的基础,例如
autocomplete=“nope”
;自动填充机制将跳过它无法识别的
autocomplete
属性值的任何字段

实现此决策的代码,用于记录:

自动完成

“自动完成”功能提供了此表单字段中以前提交的值的下拉列表。此下拉列表没有“管理地址…”选项。自动完成不支持
Autocomplete=“off”
Autocomplete=“false”
属性;任何其他值(包括“无效”值,如
Autocomplete=“nope”
)将保持启用状态

结论 自动完成下拉列表不能通过
autocomplete
下拉列表关闭;任何禁用自动填充的值都将使自动完成处于启用状态,反之亦然。任何认为自己找到了有效解决方案的人(通过
autocomplete
或其他方法,如CSS破解)应该检查它是否对这两种机制都有效

不幸的是,要说服Chrome的开发人员这是一个失败的过程,这可能会是一场艰苦的斗争。Autofill的开发人员显然相信他们做出了一个有计划的决定来打破
autocomplete=“off”
同时为web开发人员提供了一个替代方案;这个替代方案被打破了,原因比他们意识到的更微妙。从他们的角度来看,结果来自于心怀不满的开发人员,他们懒得跳过一个小圈子,更新他们的
autocomplete=“off”
属性。在所有的噪音中,信息都没有通过:箍圈坏了。

正如所解释的,必须禁用
自动填充
自动完成
功能,这在单个输入中似乎是不可能的。
我找到的唯一有效解决方案是在输入上设置
autocomplete=“off”
,并在真正的输入之前添加隐藏的假输入,以愚弄
autofill
,如下所示:

<input name="Fake_Username" id="Fake_Username" type="text" style="display:none">
<input name="Fake_Password" id="Fake_Password" type="password" style="display:none">
<input name="NameInput" id="NameInput" type="text" autocomplete="off">

*此答案不正确。我发布了一个更好(但更难看)的解决方案作为新答案,并保留了此答案,因为某些部分可能仍然有用。如果这不是处理stackoverflow错误答案的方法,请随意删除此答案*

考虑使用autocomplete=,其中每个字段和跨页面加载都是唯一的

例如,如果某个字段是在时间戳TS请求页面后创建的第N个字段,则可以将其选择为nope_u;

对自动完成的影响:由于是自动完成的自定义值,chromium不会激活自动完成功能(请参阅)

对自动填充的影响:chromium通过将其指纹与以前遇到的字段进行比较来识别字段(请参阅)。如果识别,它可能会提供一个记忆值列表。指纹包含autocomplete属性的值。由于没有两个nonce相等,因此无法识别任何字段

注:

  • 与gasman的回复相比,此处使用的术语autocomplete和autofill被替换

  • 应动态创建所有字段
    Array.prototype.slice.call(document.body.getElementsByTagName('INPUT'))
       .forEach(function(elt) { elt.name += '!' + new Date().getTime(); });
    
    function disableInputSuggestions(form) { // note: code uses ECMA5 features 
        // tweak the inputs of form 
        var inputs = Array.prototype.slice.call(form.getElementsByTagName('INPUT'));
        var nonce = Date.now();
        inputs.forEach(function(input, i) { 
            input.autocomplete = 'nope'; // prevent autocomplete
            input.originalName = input.name || input.id; // to not let this code break form handling of inputs without names (browsers fallback to the id in that case)
            input.name = nonce + '_' + i; // prevent autofill (if you're willing to eliminate all input ids first, then clear the name instead)
        });
        // replace the default submit handler by a custom one 
        form.onsubmit = function(ev) {
            // get the form data using the original variable names
            var formData = new FormData();
            inputs.forEach(function(input) { formData.set(input.originalName, input.value); });
            // submit the form data using XMLHttpRequest (alternatively, use a helper form or temporarily undo the tweaks to form) 
            var submitter = new XMLHttpRequest();
            submitter.open(form.getAttribute('method'), form.getAttribute('action'));
            submitter.onreadystatechange = function() {
                if(submitter.readyState == 4 && submitter.status == 200) {
                    // handle the server response, here assuming the default form.target = "_self"  
                    document.open();
                    document.write(submitter.responseText);
                    document.close();
                }
            }
            submitter.send(formData);
            return false; // prevent submitting form
        }; 
    }
    disableInputSuggestions(document.forms.myForm); // assumed: the form has id = myForm
    
    // Désactivation de l'autocomplete des input text
    function setAutocomplete(val) {
        var E = document.getElementsByTagName('INPUT');
        for (var i = 0 ; i < E.length ; i++) {
            if (E[i].name == 'txt_nom') { console.log('txt_nom', E[i]); }
            var type = E[i].type.toUpperCase();
            if (E[i].autocomplete != '') { continue; }
            if (type == 'HIDDEN') {
                //
            } else if (type == 'NUMBER') {
                E[i].autocomplete = 'off';
            } else if ((type == 'TEL') || (type == 'EMAIL') || (type == 'SEARCH')) {
                E[i].autocomplete = 'disabled';
            } else {
                E[i].autocomplete = val;
            }
        }
    }
    
    // Exécution de diverses fonctions à la fin de chaque chargement
    window.addEventListener("load", function() {
        // Désactivation de l'autocomplete des input text
        setAutocomplete('off');
    });
    
    --HTML--
    <input type="text" name="example" autocomplete="off">
        
    --Javascript--
    let elements = document.querySelectorAll('[autocomplete="off"]');
    elements.forEach(element => {
        element.setAttribute("readonly", "readonly");
        element.style.backgroundColor = "inherit";
        setTimeout(() => {
            element.removeAttribute("readonly");
        }, 500);
    })
    
    <input type="text" name="firstname" autocomplete="<?= bin2hex(random_bytes(10)) ?>" />