一、现象:
框架: angular 环境:chrome最新版
谷歌浏览器记住密码后,输入框为 password 类型时,就会自动展示已经保存的用户名密码列表;
如下图所示:
代码如下:
<!-- 登录密码输入框代码 -->
<input nz-input [placeholder]="'Please input the password' | translate" formControlName="password" type="password" />
解决方案:
方案一尝试:在原来基础上添加属性 autocomplete=“new-password”,结果失败,点击密码框还是会出现记住的密码列表;
方案二尝试:通过设置 readonly 属性,根据失去焦点,获取焦点来控制 readonly属性,结果成功;附上代码:
声明三点:
1. 我为什么要加 id? 为了获取到该dom节点。
2.我什么在焦点控制事件中把 id作为参数传递过去?因为当前页面有两个类型为密码框的输入框,以便复用。
3. 焦点控制事件能否不使用延时?不可以,如果不使用延时,无法正常调用,鼠标已经点击了,但是此时输入框还会是只读状态。
罗嗦完了,上正确代码:
HTML代码
<!-- 注册页面登录密码输入框 增加【id autocomplete readonly onfocus onblur】属性 -->
<input nz-input [placeholder]="'Please input the password' | translate" formControlName="password" type="password" id="pwd" autocomplete="off" readonly onfocus="removeAttr('pwd')" onblur="setAttr('pwd')" />
<!--确认密码输入框 -->
<input nz-input [placeholder]="'Please input the password again' | translate" formControlName="confirmPw" type="password" id="confirmPw" autocomplete="off" readonly onfocus="removeAttr('confirmPw')" onblur="setAttr('confirmPw')" />
JS 代码
export class RegisterComponent implements OnInit, AfterViewInit {
constructor(
...
) {
window['removeAttr'] = this.removeAttr.bind(this);
window['setAttr'] = this.setAttr.bind(this);
}
.....
// 移除密码框类型的只读属性
public removeAttr(idName) {
setTimeout(() => {
document.getElementById(idName).removeAttribute('readonly');
}, 300)
}
// 增加密码框类型的只读属性
public setAttr(idName) {
setTimeout(() => {
document.getElementById(idName).setAttribute("readonly", 'true');
}, 300)
}
}
效果:
目前虽然正常操作的话效果正常,但是经过测试也存在下列缺点,待解决,解决后再来更新:
1. 鼠标在输入框里面连续点击,密码提示列表会再次展示;
2. 当输入密码,然后再把密码删除为空的时候,密码提示列表也会再次展示;
5.14更新:上次遗留的这个两个问题终于解决了, 参考了链接:https://blog.csdn.net/qq_35264415/article/details/105160728
最终完美解决版:
HTML部分不变:
<!-- 之前的两个输入框代码没有变动 -->
<input nz-input [placeholder]="'Please input the password' | translate" formControlName="password" type="password" id="pwd" autocomplete="off" readonly onfocus="removeAttr('pwd')" onblur="setAttr('pwd')" />
<input nz-input [placeholder]="'Please input the password again' | translate" formControlName="confirmPw" type="password" id="confirmPw" autocomplete="off" readonly onfocus="removeAttr('confirmPw')" onblur="setAttr('confirmPw')" />
JS部分:
// 移除密码框类型的只读属性
public removeAttr(idName) {
document.getElementById(idName).addEventListener('click', this.handleClick);
document.getElementById(idName).addEventListener('keydown', this.handleKeydown);
document.getElementById(idName).addEventListener('mousedown', this.handleMousedown);
//使用setTimeout,告诉JS是异步执行,这样子,就可以阻止第一次点击获取焦点时,下拉用户密码清
//单的框的出现
setTimeout(() => {
//获取焦点时 同时去除只读,这样可以获取光标,进行输入
document.getElementById(idName).removeAttribute('readonly');
}, 300)
}
// 增加密码框类型的只读属性
public setAttr(idName) {
//失去焦点立马更新为只读
document.getElementById(idName).setAttribute("readonly", 'true');
}
// 点击事件
private handleClick(e) {
//为什么先失去焦点,在获取焦点,这样子可以避免第二次或更多次连续点击输入框时,出现的用户密
// 码清单的框可以快速去除
if (e.type === 'click') {
document.getElementById(e.target.id).blur();
document.getElementById(e.target.id).focus();
}
}
// 监听键盘输入事件
// 当keyCode=8(backspace键) 和 keyCode=46(delete键)按下的时候,判断只剩下最后一个字符的时
// 候阻止按键默认事件,自己清空输入框
// 当keyCode=8(backspace键) 和 keyCode=46(delete键)按下的时候,判断如果处于全选状态,就阻
// 止按键默认事件,自己清空输入框
// 这种用来避免删除最后一个字符完后出现下拉用户密码清单的框
private handleKeydown(e) {
if (e.type === 'keydown') {
const keyCode = e.keyCode;
// 和JS不一样,TS中写法如此,不然报类型“HTMLElement”上不存在属性“value”
const passwordText = (<HTMLInputElement>document.getElementById(e.target.id));
if (keyCode === 8 || keyCode === 46) {
//backspace 和delete
const len = passwordText.value.length;
if (len === 1) {
passwordText.value = "";
return false;
}
if (e.target.selectionStart === 0 && e.target.selectionEnd === len) {
passwordText.value = "";
return false;
}
}
return true;
}
}
//用来阻止第二次或更多次点击密码输入框时下拉用户密码清单的框一闪而过的问题
private handleMousedown(e) {
if (e.type === 'mousedown') {
document.getElementById(e.target.id).blur();
document.getElementById(e.target.id).focus();
}
}
效果: