zoukankan      html  css  js  c++  java
  • 改变input的值不会触发change事件的解决思路

    通常来说,如果我们自己通过 value 改变了 input 元素的值,我们肯定是知道的,但是在某些场景下,页面上有别的逻辑在改变 input 的 value 值,我们可能希望能在这个值发生变化的时候收到通知。于是我们想到了 onchange 事件,然而我们遗憾的发现,onchange 事件却并不会被触发,因为onchange事件触发是有条件的。

    onchange 事件的触发条件

    onchange 触发需要三个步骤:

    1. input 元素获得焦点
    2. input 元素的值发生变化
    3. input 元素失去焦点

    而且必须是点击触发的,这句话的意思是,尽管我们可以通过 input.focus() 使 input 元素获得焦点,可以通过 input.value 改变值,可以通过 input.blur() 使元素失去焦点,但是这并不会触发 onchange 事件,可以看下面的 demo 一探究竟:

    如何在改变 value 时获得通知

    一种方法是使用 timer。通过 setInterval 的方式来不断查看 value 值是否发生变化。这种方法虽然可以 work,但是实时性不是很好,也比较浪费资源。所以有没有第二种方法呢,答案是本文接下来要说的 -- 重写 value 属性

    其实这种操作尽管不推荐,但是还是比较常见的。比如 Vue,通过重写 Array 的 push,pop,concat 等方法,从而实现了只要对数组进行上述操作,就能触发界面更新。那么接下来,我们来尝试重写 input 元素的这个 value 属性,实现改变 value 值时,我们可以得到通知。

    可以判断的是,value 绝对不是一个简单的值,所以我们先看看 value 是如何定义的:

    let input = document.querySelector(input);
    console.log(Object.getOwnPropertyDescriptor(input, 'value'))
    

    可以看到打印出来是 undefined,所以 value 这个属性是 input 元素继承过来的,也就是位于 HTMLInputElement 的 prototype 上 -- input.constructor.prototype 或者 input.__proto__。于是将上面的代码改一下:

    console.log(Object.getOwnPropertyDescriptor(input.__proto__, 'value'))
    
    

    打印结果如下:
    uploading-image-256926.png

    于是我们知道了 value 是挂在 input 元素原型对象上的一个 getter 和 setter 的属性。那么接下来,我们只要改写 setter,在 setter 中加入通知代码,然后同时调用原来的 setter,就可以检测 value 的变化。代码如下:

    let descriper = Object.getOwnPropertyDescriptor(input.__proto__, 'value');
    // 取出原先的 get 和 set 函数
    let getValue = descriper.get;
    let setValue = descriper.set;
    
    Object.defineProperty(
      input.__proto__, 
      'value', 
      {
        configurable: true,
        enumerable: true,
        get: function (){
          return getValue.call(this);
        },
        // 重写 set 方法
        set: function (){
          console.log(arguments, this);
          // 加入通知代码
          $(this).trigger('valChange');
          setValue.call(this, ...arguments);
        }
      })
    

    下面是一个 demo,可以看到,点击 button 设置 value 时,可以被看到控制台打印出 value 发生变化。

    总结

    在通过 js 设置 value 时,无法触发 onchange 事件,这里这个问题提供了另外一种解决思路,基本思想上写一个新的函数替换原有 value 属性的 setter,在新函数中加入自己的逻辑后调用原有的 setter。(本文完)

  • 相关阅读:
    如何Android Apk反编译得到Java源代码
    安卓反编译揭秘!!
    Android Apk反编译得到Java源代码
    玩手游虽易保安全不易,打造手游App定制加密方案
    LR学习笔记2-LoadRunner目录分析
    LR学习笔记1-性能测试常见用语
    [MySql视图的使用]
    SQL实训
    Mysql_删除主键
    [SQL提数]函数的灵活使用
  • 原文地址:https://www.cnblogs.com/imgss/p/10279776.html
Copyright © 2011-2022 走看看