实现一个动态脱敏指令,输入时候显示真实数据,展示的时候进行脱敏

说在前面

🎈所谓的数据脱敏,是指在不影响数据分析结果的准确性前提下,对原始数据中的敏感字段进行处理,从而降低数据敏感度和减少个人隐私风险的技术措施。在现在这个大数据时代,个人隐私信息在互联网上传播的几率是很大的,因此作为前端工程师,我们很多时候也需要在视图层面对数据进行脱敏展示处理。

效果展示

体验地址

jyeontu.xyz/jvuewheel/#...

指令实现

脱敏函数

参数处理

  • 接受三个参数 str (待脱敏的字符串)、config (脱敏配置对象)和 fn (可选的自定义处理函数)。首先对 str 进行了 trim 操作并强制转换为字符串类型,确保输入数据的规范性。
  • 若存在自定义函数 fn,则直接调用该函数并返回结果,给予开发者灵活定制脱敏逻辑的空间。
  • str 为空字符串时,直接返回空,简洁处理边界情况。
javascript 复制代码
const desensitization = (str, config, fn) => {
    str = str.trim() + "";
    if (fn) {
        return fn(str);
    }
    if (!str) {
        return "";
    }
    ............
}

配置解析与默认值设定

  • config 中解构出 before (脱敏前保留的字符数)和 after (脱敏后保留的字符数),并提供了默认值 0 。同时获取 type (数据类型标识,如 phoneemail 等)和 ch (用于替换敏感字符的符号,默认为 *)。
  • 根据不同的 type ,对 beforeafter 进行了智能的默认值调整。例如对于 phone 类型,若字符串长度小于 11 ,则合理调整 before 为 2,after 为 2,以适配常见的手机号码格式;对于 email 类型,则根据 @ 符号分割字符串来确定 after 的值,精准定位域名部分进行保护。
javascript 复制代码
let { before = 0, after = 0 } = config;
const { type, ch = "*" } = config;
const len = str.length;
switch (type) {
    case "phone":
        before = "3";
        after = "4";
        if (len < 11) {
            before = 2;
            after = 2;
        }
        break;
    case "email":
        before = "1";
        if (str.split("@").length > 1) after = str.split("@")[1].length + 1;
        break;
    case "idCard":
        before = "3";
        after = "4";
        break;
    case "name":
        before = "1";
        after = len > 2 ? 1 : 0;
        break;
}

构造正则进行脱敏

计算出需要显示的真实字符数 show ,基于此构建正则表达式 reg 。通过 replace 方法,按照正则表达式的匹配规则,用指定的 ch 符号替换中间的敏感字符,最终返回脱敏后的字符串。

javascript 复制代码
const show = Math.max(len - before - after, 0);
const reg = [
    new RegExp(`^(.{${before}}).{${show}}(.{${after}})$`),
    `$1${ch.repeat(show)}$2`,
];
return str.replace(reg[0], reg[1]);

指令执行函数

参数提取与初始值获取

从指令绑定的值 binding.value 中提取出 params ,进一步解构得到 configfn 。同时获取元素 el 的相关属性值,如 innerHTMLgetAttribute 获取的原始值 originVal ,并初始化 inputOriginVal,为后续处理用户输入做准备。

javascript 复制代码
const params = binding.value || {};
const { config, fn } = params;
let inputOriginVal = "";
let originVal = el.getAttribute("desensitization-originVal") || "";

文本节点脱敏处理

el.innerHTML 存在时,意味着是对页面展示的文本内容进行脱敏。首先确保 originVal 的获取,若为空则从 el.innerText 中获取并设置为原始值,存储在自定义属性 desensitization-originVal 中,然后调用 desensitization 函数对 originVal 进行脱敏处理,并更新 el.innerHTML

javascript 复制代码
if (el.innerHTML) {
    if (!originVal) {
        el.setAttribute("desensitization-originVal", el.innerText);
        originVal = el.innerText;
    }
    el.innerHTML = desensitization(originVal, config, fn);
    return;
}

输入框交互处理

针对输入框元素,先移除之前可能存在的焦点和失焦事件监听器,避免重复绑定。然后分别为 focusblur 事件添加监听器。在 focus 事件中,将输入框的值恢复为原始输入值 inputOriginVal ;在 blur 事件中,获取当前输入值 value ,更新 inputOriginVal ,并调用 desensitization 函数对 value 进行脱敏处理,最后更新输入框的显示值。

javascript 复制代码
if (fouceListerner) {
    el.removeEventListener("focus", fouceListerner);
}
fouceListerner = el.addEventListener("focus", (event) => {
    event.target.value = inputOriginVal;
});
if (blurListerner) {
    el.removeEventListener("blur", blurListerner);
}
blurListerner = el.addEventListener("blur", (event) => {
    const value = event.target.value;
    inputOriginVal = value;
    const newVal = desensitization(value, config, fn);
    event.target.value = newVal;
});

指令生命周期钩子

bind

当指令首次绑定到元素上时执行。在此处调用 doDesensitization 函数,尝试进行脱敏处理,若出现错误则捕获并打印 bindErr 相关的错误信息,确保指令初始化的稳定性。

javascript 复制代码
bind: function (el, binding) {
    try {
        doDesensitization(el, binding);
    } catch (err) {
        console.error("bindErr", err);
    }
}

update

当指令所在组件的数据更新时触发。首先判断元素 elinnerText 是否存在,若存在则调用 doDesensitization 函数进行重新脱敏处理,同样对错误进行捕获并打印 updateErr,保证数据更新后的脱敏效果持续有效。

javascript 复制代码
update: function (el, binding) {
    if (!el.innerText) return;
    try {
        doDesensitization(el, binding);
    } catch (err) {
        console.error("updateErr", err);
    }
}

unbind

当指令从元素上移除时执行。主要任务是移除之前绑定的焦点和失焦事件监听器。

javascript 复制代码
unbind: function (el) {
    if (fouceListerner) {
        el.removeEventListener("focus", fouceListerner);
    }
    if (blurListerner) {
        el.removeEventListener("blur", blurListerner);
    }
}

指令使用

电话号码脱敏

内置有电话的脱敏类型,对于11位数的手机号码,脱敏方式是显示前3位和后4位;对于小于11位数的,比如7位数的电话号码,脱敏方式是显示前2位和后2位。

html 复制代码
<div class="content">
    <input
        v-JDesensitization:params="params"
        placeholder="输入需要脱敏的字符"
        class="input-content"
    />
    <div v-JDesensitization:params="params" class="div-content">
        15012345678
    </div>
</div>
<script>
export default{
    data(){
        return {
            params:{
                "config": {
                    "type": "phone",
                    "before": ,
                    "after": "",
                    "ch": "*"
                },
                "fn": ""
            },
        }
    }
}
</script>

身份证号码脱敏

内置有身份证号码的脱敏类型,脱敏方式是显示前3位和后4位;

html 复制代码
<div class="content">
    <input
        v-JDesensitization:params="params"
        placeholder="输入需要脱敏的字符"
        class="input-content"
    />
    <div v-JDesensitization:params="params" class="div-content">
        330621199909091234
    </div>
</div>
<script>
export default{
    data(){
        return {
            params:{
                "config": {
                    "type": "idCard",
                    "before": ,
                    "after": "",
                    "ch": "*"
                },
                "fn": ""
            },
        }
    }
}
</script>

姓名脱敏

内置有姓名的脱敏类型,两个字的姓名脱敏方式是显示第1位;大于两个字的姓名脱敏方式是显示第一个字和最后一个字。

html 复制代码
<div class="content">
    <input
        v-JDesensitization:params="params"
        placeholder="输入需要脱敏的字符"
        class="input-content"
    />
    <div v-JDesensitization:params="params" class="div-content">
        张三风
    </div>
</div>
<script>
export default{
    data(){
        return {
            params:{
                "config": {
                    "type": "name",
                    "before": ,
                    "after": "",
                    "ch": "*"
                },
                "fn": ""
            },
        }
    }
}
</script>

邮箱脱敏

内置有邮箱的脱敏类型,脱敏方式是显示第一位和@及以后的字符。

html 复制代码
<div class="content">
    <input
        v-JDesensitization:params="params"
        placeholder="输入需要脱敏的字符"
        class="input-content"
    />
    <div v-JDesensitization:params="params" class="div-content">
        123456@163.com
    </div>
</div>
<script>
export default{
    data(){
        return {
            params:{
                "config": {
                    "type": "email",
                    "before": ,
                    "after": "",
                    "ch": "*"
                },
                "fn": ""
            },
        }
    }
}
</script>

自定义脱敏

  • 可以自定义脱敏代替字符,默认为*

修改 config 中的 ch 参数即可自定义脱敏代替字符

javascript 复制代码
params: {
    config: {
        type: "phone",
        before: "",
        after: "",
        ch: "~",
    },
    fn: "",
}
  • 可以自定义脱敏字符头尾显示位数

修改 config 中的 beforeafter 参数即可自定义脱敏显示位数,type 需要修改为内置类型以外的,直接传空即可。

javascript 复制代码
params: {
    config: {
        type: "",
        before: "2",
        after: "2",
        ch: "~",
    },
    fn: "",
}
  • 可以自定义脱敏函数进行脱敏

可以直接在参数的 fn 中传入一个脱敏函数,如果传入了 fn ,其优先级最高,则其他参数都不会生效,会直接调用传入的 fn函数 进行脱敏,如:

javascript 复制代码
(str) => {
  return str[0] + '@'.repeat(str.length - 1);
}

应用场景

用户信息填写,输入框聚焦时显示真实数据 供用户进行修改,失焦时显示脱敏后的数据

(至于为什么会有这个场景,需要去问一下产品经理😏)

组件库

组件文档

目前该指令也已经收录到我的组件库,组件文档地址如下: jyeontu.xyz/jvuewheel/#...

组件内容

组件库中还有许多好玩有趣的指令,如:

  • 千分位分隔
  • 防抖指令
  • 拖拽指令
  • 缩放指令
  • 数字转大写中文

等等......

组件库源码

组件库已开源到gitee,有兴趣的也可以到这里看看:gitee.com/zheng_yongt...

🌟觉得有帮助的可以点个star~

🖊有什么问题或错误可以指出,欢迎pr~

📬有什么想要实现的组件或想法可以联系我~

公众号

关注公众号『前端也能这么有趣』,获取更多有趣内容。

发送『组件库』获取源码

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

最后的最后

最后再给自己拉个票,还有票的大佬们可以投我一票,感谢大家🥰🥰🥰

掘金2024年度人气创作者打榜中,快来帮我打榜吧~ activity.juejin.cn/rank/2024/w...

相关推荐
道不尽世间的沧桑2 小时前
第17篇:网络请求与Axios集成
开发语言·前端·javascript
diemeng11193 小时前
AI前端开发技能变革时代:效率与创新的新范式
前端·人工智能
bin91535 小时前
DeepSeek 助力 Vue 开发:打造丝滑的复制到剪贴板(Copy to Clipboard)
前端·javascript·vue.js·ecmascript·deepseek
晴空万里藏片云6 小时前
elment Table多级表头固定列后,合计行错位显示问题解决
前端·javascript·vue.js
曦月合一6 小时前
html中iframe标签 隐藏滚动条
前端·html·iframe
奶球不是球6 小时前
el-button按钮的loading状态设置
前端·javascript
kidding7236 小时前
前端VUE3的面试题
前端·typescript·compositionapi·fragment·teleport·suspense
无责任此方_修行中8 小时前
每周见闻分享:杂谈AI取代程序员
javascript·资讯
Σίσυφος19008 小时前
halcon 条形码、二维码识别、opencv识别
前端·数据库
学代码的小前端8 小时前
0基础学前端-----CSS DAY13
前端·css