说在前面
🎈所谓的数据脱敏,是指在不影响数据分析结果的准确性前提下,对原始数据中的敏感字段进行处理,从而降低数据敏感度和减少个人隐私风险的技术措施。在现在这个大数据时代,个人隐私信息在互联网上传播的几率是很大的,因此作为前端工程师,我们很多时候也需要在视图层面对数据进行脱敏展示处理。
场景
在一个页面上,我们需要客户输入手机号码、身份证号码等敏感信息,客户要求在输入的时候可以对输入内容进行脱敏处理,同时原始数据需要保存到数据库,如下图:
脱敏格式:保留身份证号码的前四位和后六位,中间使用*号代替
。
体验
难点分析
接到需求后我们需要先对其进行简单分析,可以得出大致有以下几个问题需要处理。
- 1、input框输入值与展示值分离;
- 2、对展示值进行修改时,需要同步修改真实值;
- 3、真实值与展示值同步动态转换。
- 4、光标位置需要重设;
功能实现
想要实现该功能只需要将前面分析得出的难点一一克服,我们就可以实现该功能。
1、input框输入值与展示值分离
这个问题其实比较好解决,我们可以添加两个变量,分别保存输入的真实数据和脱敏后的展示数据。
<template>
<div>
<div class="form-item">身份证号码脱敏(显示前4位和后6位)</div>
<input class="form-item"
v-model="showValue"
placeholder="请输入身份证号码"
@input="desenInputText"
/>
<div class="form-item">输入数据</div>
<div class="form-item"> {{ value }} </div>
</div>
</template>
如上代码,我们分别使用showValue和value两个变量来保存脱敏后的展示数据和输入的真实数据。
2、对展示值进行修改时,需要同步修改真实值
我们可以给input框绑定input事件,每次输入时对真实值和展示值进行动态转换,具体转换方法后面会说到。
desenInputText(e) {
//真实值与展示值同步动态转换
},
3、真实值与展示值同步动态转换
3.1 末尾追加 or 删除
这里是该功能真正意义上的第一个难点,我们需要同时维护两个变量的值,主要有以下四种场景:
- 1、输入单个字符
如上图,此时的展示值为1234***891011
,真实值为1234567891011
,如果此时我们在最后追加一个字符2
,应该需要进行怎样地处理?其实只需要两步:
(1)将输入的`2`拼接到真实值后面,此时真实值变为`12345678910112`;
(2)再对真实值进行脱敏得到展示值`1234****910112`。
- 2、复制输入多个字符
如果此时我们并不是在最后追加一个字符,而是需要将剪切板的多个字符(如:234
)追加到数据后面呢?我们需要进行以下三步操作:
(1)计算展示值和真实值之差n;
(2)将展示值的末尾n位拼接到真实值后面,此时真实值变为`1234567891011234`;
(3)再对真实值进行脱敏得到展示值`1234******011234`。
- 3、删除单个字符
删除单个字符时我们只需要将真实值末尾的字符输出,再重新转换展示值即可。
- 4、选中删除多个字符
删除多个值的时候,我们需要进行以下三步操作:
(1)计算展示值和真实值之差n;
(2)删除真实值的末尾n位;
(3)对真实值进行脱敏得到展示值。
3.2 非末尾插入 or 删除
前面我们看了在末尾插入或者删除的4种场景,知道了简单场景下的动态转换方法,那么将修改位置移动到字符串中间呢?暂停五分钟思考一下我们应该要怎么做?\
5\
.\
.\
.\
4\
.\
.\
.\
3\
.\
.\
.\
2\
.\
.\
.\
1\
.\
.\
.\
0\
有了大致思路了吗?我们接着往下进行:\
插入位置变了,那如果我们可以找到插入位置,我们是不是可以将插入的开始位置看成是末尾,在这个位置插入增量数据或者删除掉减量数据即可?所以我们需要进行以下四步:\
(1)获取当前光标位置ind;
(2)计算展示值和真实值之差n;
(3)在输入起始位置(ind-n+1)插入增量数据;
(4)对真实值进行脱敏得到展示值。
具体代码如下
//输入框动态脱敏
desenInputText(e) {
const ind = e.target.selectionStart - 1;
let value = this.value;
const showValue = this.showValue;
const isAdd = showValue.length > value.length;
const num = Math.abs(value.length - showValue.length);
if (isAdd) {
value =
value.slice(0, ind-num+1) +
showValue.slice(ind-num+1,ind+1) +
value.slice(ind-num+1);
} else {
value = value.slice(0, ind + 1) + value.slice(ind + num + 1);
}
this.value = value;
this.showValue = this.desenText(value);
},
4、光标位置需要重设
写完上面的代码后已经可以大致实现数据动态脱敏的功能,但是试了几遍后我们会发现,每次输入后光标都会自动移动到输入框的最后面,我们还需要处理一下这个问题,将光标保持在原来的位置上。
const elem = e.target;
if (elem.setSelectionRange) {
// 标准浏览器
elem.setSelectionRange(ind + 1, ind + 1);
} else {
// IE9-
const range = elem.createTextRange();
range.moveStart('character', ind + 1);
range.moveEnd('character', ind + 1);
range.select();
}
完整代码
<template>
<div>
<div class="form-item">身份证号码脱敏(显示前4位和后6位)</div>
<input class="form-item"
v-model="showValue"
@input="desenInputText"
placeholder="请输入身份证号码"
/>
<div class="form-item">输入数据</div>
<div class="form-item"> {{ value }} </div>
</div>
</template>
<script>
export default {
name:'desensitize-input',
data(){
return {
showValue:'',
value:''
}
},
methods:{
desenText(str) {
let res = str;
const len = str.length;
let pre4 = '';
let last6 = '';
pre4 = str.slice(0, 4);
last6 = str.slice(Math.max(len - 6, 4));
const star = Math.max(0, len - 10);
res = pre4 + '*'.repeat(star) + last6;
return res;
},
//输入框动态脱敏
desenInputText(e) {
const ind = e.target.selectionStart - 1;
let value = this.value;
const showValue = this.showValue;
const isAdd = showValue.length > value.length;
const num = Math.abs(value.length - showValue.length);
if (isAdd) {
value =
value.slice(0, ind-num+1) +
showValue.slice(ind-num+1,ind+1) +
value.slice(ind-num+1);
} else {
value = value.slice(0, ind + 1) + value.slice(ind + num + 1);
}
this.value = value;
this.showValue = this.desenText(value);
this.$nextTick(() => {
const elem = e.target;
if (elem.setSelectionRange) {
// 标准浏览器
elem.setSelectionRange(ind + 1, ind + 1);
} else {
// IE9-
const range = elem.createTextRange();
range.moveStart('character', ind + 1);
range.moveEnd('character', ind + 1);
range.select();
}
});
},
}
}
</script>
<style>
.form-item{
margin-top: 1em;
}
</style>
源码地址
Gitee源码:https://gitee.com/zheng_yongtao/jyeontu-vue-demo
觉得有帮助的同学可以帮忙给我点个star,感激不尽~~~\
有什么想法或者改良可以给我提个pr,十分欢迎~~~\
有什么问题都可以在评论告诉我~~~
说在后面
🎉这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打打羽毛球🏸 ,平时也喜欢写些东西,既为自己记录📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解🙇,写错的地方望指出,定会认真改进😊,在此谢谢大家的支持,我们下文再见🙌。