禁止浏览器记住明码、主动填写明码,反对明文暗文显示明码
应用办法:父组件中引入 handPwd.vue 组件
父组件应用:
<el-form
ref="form"
:model="form"
:rules="rules"
>
<el-form-item label="明码" key="password" prop="password">
<hand-password
ref="handPassword"
inputId="handPassword-password"
@inputPwd="inputPassword"
:needValidatePwd="false"
></hand-password>
<!-- <el-input
type="password"
v-model="form.password"
placeholder="明码"
clearable
></el-input> -->
</el-form-item>
</el-form>
import handPassword from '@/components/common/handPassword.vue'
components: {handPassword},
data(){
return {
form:{password:''},
rules:{
password: [{ required: true, message: '明码不能为空', trigger: 'blur'},
{pattern: /^[^\s\u4e00-\u9fa5]+$/, message: '不容许输出空格、中文等特殊符号' }
]
}
}
},
methods:{inputPassword(val) {
this.form.password = val
this.$refs.form.validateField('password')
}
}
handPwd.vue
<template>
<div>
<div :class="['el-input','el-input--suffix', prefixIconName !='' ? 'el-input--prefix' : '']">
<!-- 判断 account 是否为 admin,是为了给开发留个后门,方便使用浏览器记住明码哈哈 -->
<!-- 禁止复制、粘贴、剪切 -->
<input
:type="account =='admin'?'password':'text'"autocomplete="off":id="inputId"v-model="secretPwd"@input="inputPassword"@copy.prevent="() => {}"@paste.prevent="() => {}"@cut.prevent="() => {}":placeholder="placeholder":maxlength="maxLength"class="el-input__inner":style="{'padding-right': clearPwd != ''?'56px':'30px'}"
/>
<span v-show="prefixIconName !=''" class="el-input__prefix"
><i :class="prefixIconName"></i
></span>
<span class="el-input__suffix">
<span class="el-input__suffix-inner">
<i
v-show="secretPwd !==''"
@click="inputPassword({target: { value:''} })"class="el-input__icon el-icon-circle-close"style="cursor: pointer;vertical-align: middle;"
></i>
<svg-icon
v-if="showPwd"
@click="handleShowPwd"
iconClass="明文"
class="el-input__icon el-icon-view"
style="cursor: pointer;height: 32px;font-size: 12px;color: #C0C4CC;vertical-align: middle;margin-right: 6px;"
/>
<svg-icon
v-else
@click="handleShowPwd"
iconClass="暗文"
class="el-input__icon el-icon-view"
style="cursor: pointer;height: 32px;font-size: 12px;color: #C0C4CC;vertical-align: middle;margin-right: 6px;"
/> </span
></span>
</div>
<div v-show="errorPwd" class="el-form-item__error">
明码不能为空
</div>
</div>
</template>
<script>
/**
* 手写明码,不反对右键菜单、复制、黏贴、剪切
*/
export default {
name: 'handPassword',
props: {
// 输入框的 id
inputId: {
type: String,
default: 'passwordInput'
},
// 后门:用户名称,不便开发应用浏览器记住明码
account: {
type: String,
default: ''
},
// 须要应用子组件的校验,个别不应用
needValidatePwd: {
type: Boolean,
default: false
},
// 输入框的暗正文
placeholder: {
type: String,
default: '请输出明码'
},
// 输入框的最大输出长度
maxLength: {
type: Number,
default: 100
},
// 输入框头部图标类名
prefixIconName: {
type: String,
default: ''
},
// 初始化明码值,个别用于编辑表单
originPwd: {
type: String,
default: ''
}
},
data() {
return {
secretPwd: '', // 暗文明码
clearPwd: '', // 明文明码
showPwd: false, // 是否显示明文
errorPwd: false // 是否明码谬误
}
},
watch: {
/**
* 监听初始化明码,将明文和暗文明码别离初始化
*/
originPwd: {handler(val) {
this.clearPwd = val
this.secretPwd = '●'.repeat(val.length)
},
immediate: true
}
},
created() {
/**
* 禁止浏览器右键,因为右键菜单里有撤销、重写、黏贴、复制
*/
window.oncontextmenu = function(e) {e.preventDefault()
}
},
methods: {
/**
* 重置办法,个别是给父组件调用
*/
reset() {
this.showPwd = false
this.errorPwd = false
},
/**
* 查看明码
*/
checkPassword() {if (this.needValidatePwd) {if (this.clearPwd === '') {this.errorPwd = true} else {this.errorPwd = false}
}
},
/**
* 点击明码框后的小眼睛,切换明文或暗文
*/
handleShowPwd() {if (this.showPwd) {this.secretPwd = '●'.repeat(this.secretPwd.length)
} else {this.secretPwd = JSON.parse(JSON.stringify(this.clearPwd))
}
this.showPwd = !this.showPwd
},
/**
* 输出明码
*/
inputPassword(val) {
const inputVal = val.target.value // 原生 input 须要取 target.value
// 如果明文展现或者只输出了一个字符,比较简单,间接复制
if (this.showPwd || inputVal.indexOf('●') === -1) {if (this.showPwd) {this.secretPwd = inputVal} else {this.secretPwd = '●'.repeat(inputVal.length)
}
this.clearPwd = inputVal
} else {
const planeTextLen = this.clearPwd.length, // 明文长度
cipherTextLen = inputVal.length, // 暗文长度
selectionEnd = document.getElementById(this.inputId).selectionEnd // 获取光标地位
const realArr = this.clearPwd.split(''), // 实在明码数组
coverArr = inputVal.split('') // 文本框显示明码数组
let index = -1 // 新输出的字符地位
let lastChar = '' // 新输出的字符
// 找到新输出的字符及地位
coverArr.forEach((el, idx) => {if (/[^●]/g.test(el)) {
index = idx
lastChar += el
}
})
if (planeTextLen < cipherTextLen) {
// 新增
realArr.splice(index, 0, lastChar)
} else if (cipherTextLen <= planeTextLen && index !== -1) {
// 替换
realArr.splice(index, planeTextLen - (cipherTextLen - 1), lastChar)
} else {
// 删除
realArr.splice(selectionEnd, planeTextLen - cipherTextLen)
}
this.clearPwd = realArr.join('')
this.secretPwd = '●'.repeat(this.secretPwd.length)
// 还原光标地位
this.$nextTick(() => {document.getElementById(this.inputId).selectionEnd = selectionEnd
})
}
this.checkPassword()
// 告知父组件明文明码
this.$emit('inputPwd', this.clearPwd)
}
}
}
</script>