最近被这个问题纠缠了很久,前后改了三天,真的是遇到了很多坑。
首先查了下其他人的用法
- 对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
但是这种方法也有问题,只能做到在第一次点击输入框时不出现浏览器弹框,当多次点击未输入任何文字的输入框时仍会出现浏览器提示框。
总的来说,屏蔽浏览器提示已保存的账号密码这个功能,暂时还没有找到特别完美的方案。
如果有大佬知道可以告诉我一下,万分感谢。