先贴正确代码:
function inputValue(el, value) {
const prop = HTMLInputElement.prototype
const setValue = Object.getOwnPropertyDescriptor(prop, 'value').set
setValue.call(el, value);
const event = new Event('input', { bubbles: true })
el.dispatchEvent(event)
}
教程来源:https://www.zhihu.com/question/273667163?sort=created
getOwnPropertyDescriptor 教程:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/getOwnPropertyDescriptor
一般页面的输入框,只需要按照下面方法就可以实现自动输入:
input.value = 'v'
const event = new Event('input', {bubbles: true})
input.dispatchEvent(event)
理想情况下,这段代码应该会模拟一个 DOM input 事件,然后触发 React 的 change 事件。然而事实上却没有触发 change 事件.
原因是 ReactDOM 在模拟 onChange 事件的时候有一个逻辑:只有当 input 的 value 改变,ReactDOM 才会产生 onChange 事件。ReactDOM 里面有个 inputValueTracking 类是做这个事情的,其实现原理是使用一个变量 currentValue 存储 input 的最新值,并覆盖掉 input 的 value getter。当其他地方执行了 input.value = xxx 时,会执行 value getter,setter 里面用新 value 更新 currentValue。
当 DOM input 事件触发时,inputValueTracking 会判断 currentValue 和 input 的真实值是不是一致的,如果不一致,就说明发生了变化。只有发生了变化,上层调用方才会模拟出一个 change 事件。
答案是在 input.value = 'v' 这一步,想办法绕过 inputValueTracking 里面覆写的 value setter. ReactDOM 不是把 value setter 覆盖了吗,那么直接拿到原始的 value setter,call 调用就行。