Skip to content

input.value

诱因

最近在在做一个独立校验框架,在不修改原有业务的基础上,针对表单内容检验业务规则。其中有一个环节需要监听input.value的变化

input

input 标签具有同名事件input,可以通过addEventListener('input', callback)监听用户输入事件,但监听不了js改变input.value

MutationObserver

尝试通过 MutationObserver 监听dom属性的变化,但观察不到value变化

js
const input = document.querySelector('#input')

const callback = function (mutationsList, observer) {
  for (const mutation of mutationsList) {
    if (mutation.type === 'attributes')
      console.log(`The ${mutation.attributeName} attribute was modified.`)

  }
}

const observer = new MutationObserver(callback)
observer.observe(input, { attributes: true })
const input = document.querySelector('#input')

const callback = function (mutationsList, observer) {
  for (const mutation of mutationsList) {
    if (mutation.type === 'attributes')
      console.log(`The ${mutation.attributeName} attribute was modified.`)

  }
}

const observer = new MutationObserver(callback)
observer.observe(input, { attributes: true })

defineProperty

最后想到vue2 Object.defineProperty 重新定义属性

js
function observe(obj, property, cb) {
  let interval
  Object.defineProperty(obj, property, {
    get() {
      return interval
    },
    set(newVal) {
      interval = newVal
      if (typeof cb == 'function')
        cb(interval)

    }
  })
}
function observe(obj, property, cb) {
  let interval
  Object.defineProperty(obj, property, {
    get() {
      return interval
    },
    set(newVal) {
      interval = newVal
      if (typeof cb == 'function')
        cb(interval)

    }
  })
}

但是发现虽然可以重新定义属性,但不能使用interval作为值,需要使用原有的值,不然会影响业务

最终方案

由于原型链的存在,可以调用原型的 get set 函数设置原有的值

js
function observe(obj, property, cb) {
  // 获取obj的原型
  const __proto__ = Object.getPrototypeOf(obj)
  if (__proto__.hasOwnProperty(property)) {
    //  获取原型 property descriptor
    const descriptor = Object.getOwnPropertyDescriptor(__proto__, property)
    Object.defineProperty(obj, property, {
      get() {
        // 调用原型 get
        return descriptor.get.apply(this)
      },
      set() {
        // 调用原型 set
        descriptor.set.apply(this, arguments)
        if (typeof cb == 'function')
          cb(this[property])

      }
    })
  }
}
function observe(obj, property, cb) {
  // 获取obj的原型
  const __proto__ = Object.getPrototypeOf(obj)
  if (__proto__.hasOwnProperty(property)) {
    //  获取原型 property descriptor
    const descriptor = Object.getOwnPropertyDescriptor(__proto__, property)
    Object.defineProperty(obj, property, {
      get() {
        // 调用原型 get
        return descriptor.get.apply(this)
      },
      set() {
        // 调用原型 set
        descriptor.set.apply(this, arguments)
        if (typeof cb == 'function')
          cb(this[property])

      }
    })
  }
}