hugh 的个人博客

奇怪的input -前端监控之采坑篇

大坑描述

在录屏收集时, 对于部分js设置的输入框值无法获取到,但是该元素确实已加入mutation监控。

问题分析

input mutation demo

demo中可以看出

  1. input 输入框,对于不同的type, 在数据变更时,浏览器的操作是不同的
    191128input.gif

  2. 对于input 隐藏域, 无论操作的是attr还是展示value,都会反应到value属性上

  3. radio或checkbox类型,手动点击选择不会触发mutation监听

  4. textarea的效果和input普通输入框一致

解决方案

利用Object.defineProperty 修改原对象value(checked)属性的set方法, 手动监听
这边涉及到的输入Element对象如下
HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement

修改绑定代码如下:

function wrapInput(reporter) {
        function wrap(e, r) {
          var i = Object.getOwnPropertyDescriptor(e.prototype, r);
          return Object.defineProperty(e.prototype, r, {
            set: function set(e) {
              var node = this, n = mirrorNode.getId(node);
              if(n) {
                // 取该node的上一个属性值
                var last = elementMap[n];
                if(!last || (r === 'value' && last.text != e) || (r === 'checked' && last.isChecked != e)) {
                 // setTimeout的作用,用于延迟执行,便于将新属性值写入缓存
                  setTimeout(function() {
                   // 用于触发change方法
                    eventDoMap("change", reporter)({target: node, type: "change"})
                  })
                }
              }
              return i.set.call(this, e);
            }, get: function get() {
              return i.get.call(this);
            }
          }), /**该方法定义了还原方法**/function () {
            return Object.defineProperty(e.prototype, r, i);
          };
        }

        var p = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value"),
            f = [];
        p && p.set && (f = f.concat([wrap(HTMLInputElement, "value"), wrap(HTMLInputElement, "checked"), wrap(HTMLSelectElement, "value"), wrap(HTMLTextAreaElement, "value")]));

        return function () {
           // 此处用于还原重写
          f.forEach(function (e) {
            return e();
          });
        };
      }

标题:奇怪的input -前端监控之采坑篇
作者:hugh0524
地址:https://blog.uproject.cn/articles/2019/11/28/1574915423705.html