监听用户打开控制台修改dom属性内容
今天程序猿节,祝大家永无bug
昨天接了个功能,已知有一个input
类型为password
,在修改内容的时候也是密文展示,但是用户还是觉得不安全,因为可以在f12
下找到dom并直接修改input
的type
从而直接使其明文展示
wtf? 真有这么不当人的用户咩??
后来想了个办法,页面上展示的是基于此变量的计算属性比如computedStr
,然后页面上的展示本质上就是这个计算属性的值:
<el-input v-model="passwordComputed" type="password" id="pswId" style="border:1px solid red" :clearable="dialogBtn !== 'preview'" :readonly="dialogBtn == 'preview'" />
随后在计算属性里写上它的逻辑,由于它是v-model
因而要使用comp的get
&set
// computed passwordComputed: { get() { const basePasswordLen = baseMsg; //这个是该计算属性依赖的源数据 已脱敏 console.log("basePasswordLen :>> ", basePasswordLen); let encryptedStr = ``; for (let index = 0; index < basePasswordLen.length; index++) { encryptedStr += `•`; } return encryptedStr; // 当仅展示时,返回一堆`*`号,这样用户修改type也不怕啦,因为它本质上就是`*` }, set(newVal) { // 双向绑定的是计算属性, // const basePasswordLen = baseMsg; //这个是该计算属性依赖的源数据 已脱敏 // const prePsdLen = basePasswordLen.length; // 上一次的数据 // const psdEle = document.getElementById("pswId"); // console.log("psdEle :>> ", psdEle); // if (!newVal) { //如果是新值是空字符,则将原值赋空 // baseMsg = ``; // return; // } // // 如果小于原值,说明是删除动作 // if (newVal.length < prePsdLen) { // 删减动作 // } else { // const { resultVal, startIndex, filterText } = this.filterNewValue( // newVal, // basePasswordLen // ); // baseMsg = resultVal; //将计算后的数据反赋给真正的变量 // 这时候光标会异常,因为上一行是整体赋值操作而不是新增操作,因而必须要重新设置下光标 // this.$nextTick(() => { // psdEle.focus(); // 重新获取焦点 // console.log(" psdEle.selectionStart :>> ", psdEle.selectionStart); // selectionStart与selectionEnd是同一值时,显示光标所在所有,不同值时,中间的差值就是选中态 // psdEle.selectionStart = psdEle.selectionEnd = // startIndex + filterText.length + 1; // 重新设置光标 这一点非常重要,因为此input不允许明文查看,因而光标的位置就很关键。 模仿光标正常input下输入态 这里其实还要加`1`,举个例子,假设输入了四个字符,那么光标其实应该在第四位索引上 // }); // } } }
在新增动作里,添加对数据的计算
// methods // 数据清洗-》获取输入的数据和数据的第一个的下标 filterNewValue(nv, ov) { let filterText = ""; let startIndex = null; for (let index = 0; index < nv.length; index++) { if (nv[index] !== `•`) { filterText += nv[index]; if (startIndex === null) { startIndex = index; } } } const resultVal = this.insertStringAt(ov, filterText, startIndex); return { resultVal, startIndex, filterText }; }, // 此处计算用户本次输入后的明文数据(包含所有) insertStringAt(originalString, stringToInsert, insertionIndex) { if (insertionIndex < 0) { insertionIndex = 0; } if (insertionIndex > originalString.length) { insertionIndex = originalString.length; } const part1 = originalString.slice(0, insertionIndex); const part2 = originalString.slice(insertionIndex); return part1 + stringToInsert + part2; },
终于写完了,擦擦脑门汗,发现有一个大问题,我可以监听用户修改条目时的新增,无论他在开头结尾或中间,但是我却无法监听它的删减,准确的说,无法监听它删减时对应的数据和下标。
因为:passwordComputed
的值是一个基于base数据的***
,所以在删减这个数据的时候拿到的新值也只是**
眼前真的一黑...
狠狠抽了一口空气,突然想明白了一件事:当前需求是希望用户不要在f12时修改dom,那么我们就可以以此为切入点:
网上的案例是当用户打开f12时直接debugger:
mounted(){ // 监听用户f12时,直接debugger;可以但不该 ((function () { var callbacks = [], timeLimit = 50, open = false; var str = /x/ str.toString = function () { window.clearInterval = function () { return '不能使用清除定时器了' } } setInterval(loop, 1); return { addListener: function (fn) { callbacks.push(fn); }, cancleListenr: function (fn) { callbacks = callbacks.filter(function (v) { return v !== fn; }); }, }; function loop() { var startTime = new Date(); debugger; if (new Date() - startTime > timeLimit) { if (!open) { callbacks.forEach(function (fn) { fn.call(null); }); } open = true; window.stop(); console.log(str) window.location.reload(); } else { open = false; } } })()).addListener(function () { window.location.reload(); }); }
这段代码写下来,当用户一打开开发者工具时就直接进入调试态,这太粗暴,太不优雅,本着对用户负责的态度,于是放弃了这个做法(毕竟我们不能不当人不是)
然后又在想,可不可以直接监听用户在按f12对dom修改的动作,于是就找到了mutationObserve
这个api,废话不说,上代码
贴贴:
<script> let observer // 没用必要将其变成响应式,浪费性能 mounted(){ this.$nextTick(() => { // 选择需要观察变动的节点 const targetNode = document.getElementById("pswId"); // 观察器的配置(需要观察什么变动) // attributes: 观察受监视元素的属性值变更 // childList: 监视目标节点(如果 subtree 为 true,则包含子孙节点)添加或删除新的子节点 // subtree: 其他值也会作用于此子树下的所有节点,而不仅仅只作用于目标节点 const config = { attributes: true, childList: false, subtree: false }; // childList && subtree须设置为false以节省性能 // 当观察到变动时执行的回调函数 const callback = function(mutationsList, observer) { for (let mutation of mutationsList) { if (mutation.type === "attributes") { targetNode.type = "password"; // 停止监听,一定要有这一步,否则页面将直接卡死! observer.disconnect(); //关键点1 // 随即重新监听 observer.observe(targetNode, config); // 关键点2 } } }; // 创建一个观察器实例并传入回调函数 observer = new MutationObserver(callback); // 以上述配置开始观察目标节点 observer.observe(targetNode, config); } }, beforeDestroy() { // 停止观察 observer.disconnect(); }, <script>
tips1: 关键点1必须要加,否则将会死循环至浏览器崩溃
tips1: 关键点2必须要加,否则将不再监听
其实可以封装成一个指令以便在整个项目里使用,不过没时间(其实就是懒)
以上。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义