Bootstrap

浏览器记住账号密码后,在密码输入框屏蔽浏览器的弹出提示

最近被这个问题纠缠了很久,前后改了三天,真的是遇到了很多坑。

首先查了下其他人的用法

  • 对autoComplete属性肤质为“new-password",但是这个属性在某些浏览器是不生效的(pass)
  • 将密码框的type修改为text,将输入的密码值替换为密码的圆心(这个看起来是可行的,但是有个巨坑)
  • 利用readonly属性和聚焦事件,失焦事件,鼠标按下和抬起事件(这个是我最后使用的方案,但是也有问题)

第一种不多说,第二种写了一个替换方法如下:

const changePosLocation = (idName: string, length: number) => {
        const input = document.getElementById(idName) as HTMLInputElement; // 获取input节点
        input.focus();
        setTimeout(() => {
            input.selectionStart = input.selectionEnd = length;
        }, 0);
    };
function passwordChangeVal(e: React.ChangeEvent<HTMLInputElement>) {
            const value = e.target.value;
            const realArr = store.password.split(""); // 真实密码数组
            const coverArr = value.split(""); // 文本框显示密码数组
            const coverLen = value.length; // 文本框字符串长度
            const realLen = store.password.length; // 真实密码长度
            // 找到新输入的字符及位置
            const indexArr: number[] = [];
            const elementArr: string[] = [];
            coverArr.forEach((element, idx) => {
                if (element !== "●") {
                    indexArr.push(idx);
                    elementArr.push(element);
                }
            });

            if (realLen < coverLen) {
                // 新增字符or替换的字符长度大于原字符长度
                if (coverLen - realLen === elementArr.length) {
                    realArr.splice(indexArr[0], 0, elementArr.join(""));
                } else if (coverLen - realLen < elementArr.length) {
                    const replaceLength = Number(elementArr.length - (coverLen - realLen));
                    realArr.splice(indexArr[0], replaceLength, elementArr.join(""));
                }
                changePosLocation("cover", indexArr[0] + elementArr.length);
            } else if (coverLen <= realLen && indexArr.length > 0) {
                // 替换字符(选取一个或多个字符直接替换)
                if (coverLen === realLen) {
                    realArr.splice(indexArr[0], elementArr.length, elementArr.join(""));
                } else {
                    realArr.splice(indexArr[0], realLen - (coverLen - 1), elementArr.join(""));
                }
                changePosLocation("cover", indexArr[0] + elementArr.length);
            } else {
                // 删除字符
                const pos = (document.getElementById("cover") as HTMLInputElement).selectionEnd || 0; // 获取光标位置
                realArr.splice(pos, realLen - coverLen);
            }
            // 将 coverPassword 替换成 ●
            store.coverPassword = value.replace(/[\S\s]/g, "●");
            store.password = realArr.join("");
        
    }

在input组件中的onChange事件中调用passwordChangeVal()方法

其中changePosLocation方法是为了改变光标的位置(如果不加上这个方法,在密码框的前中位置输入时,光标总会跳到最后)

这种方法在谷歌浏览器是没有问题的,但是!在其他浏览器中的表现就会出现各种各样的问题。

以谷歌内核的edg浏览器为例:切换成中文输入法输入密码时,26个字母为重复渲染4次,数字会重复渲染2次。

排查了很久后发现是”value.replace(/[\S\s]/g, "●")“这一行造成的,但是还没找到解决方法,所以打算重新换一种方式,也就是利用readOnly属性。

第三种方法通过监听聚焦和失焦事件来改变input框readonly属性

当聚焦时,将readonly改为false,失焦时改为true,然后异步改为false

但是这种方法也有问题,只能做到在第一次点击输入框时不出现浏览器弹框,当多次点击未输入任何文字的输入框时仍会出现浏览器提示框。

总的来说,屏蔽浏览器提示已保存的账号密码这个功能,暂时还没有找到特别完美的方案。

如果有大佬知道可以告诉我一下,万分感谢。

;