Live2d Test Env

监听用户打开控制台修改dom属性内容

今天程序猿节,祝大家永无bug

昨天接了个功能,已知有一个input类型为password,在修改内容的时候也是密文展示,但是用户还是觉得不安全,因为可以在f12下找到dom并直接修改inputtype从而直接使其明文展示

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必须要加,否则将不再监听

其实可以封装成一个指令以便在整个项目里使用,不过没时间(其实就是懒)

以上。

posted @   致爱丽丝  阅读(96)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示