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 @ 2023-10-24 11:14  致爱丽丝  阅读(27)  评论(0编辑  收藏  举报