如何以编程方式填充使用React构建的输入元素?

Tim*_*nen 15 javascript automation web-crawler reactjs

我的任务是抓取使用React构建的网站.我正在尝试填写输入字段并使用javascript注入页面提交表单(在移动设备中使用selenium或webview).这就像每个其他网站+技术的魅力,但React似乎是一个真正的痛苦.

所以这是一个示例代码

var email = document.getElementById( 'email' );
email.value = 'example@mail.com';
Run Code Online (Sandbox Code Playgroud)

我在DOM输入元素上更改了值,但React不会触发change事件.

我一直在尝试各种不同的方法来让React更新状态.

var event = new Event('change', { bubbles: true });
email.dispatchEvent( event );
Run Code Online (Sandbox Code Playgroud)

徒劳无功

var event = new Event('input', { bubbles: true });
email.dispatchEvent( event );
Run Code Online (Sandbox Code Playgroud)

不工作

email.onChange( event );
Run Code Online (Sandbox Code Playgroud)

不工作

我无法相信与React的互动变得如此困难.我非常感谢任何帮助.

谢谢

Dmy*_*yuk 16

这是输入、选择、复选框等最干净的解决方案(不仅适用于反应输入)

/**
 * See [Modify React Component's State using jQuery/Plain Javascript from Chrome Extension](/sf/ask/2881620381/)
 * See https://github.com/facebook/react/issues/11488#issuecomment-347775628
 * See [How to programmatically fill input elements built with React?](/sf/ask/2862624621/)
 * See https://github.com/facebook/react/issues/10135#issuecomment-401496776
 *
 * @param {HTMLInputElement | HTMLSelectElement} el
 * @param {string} value
 */
function setNativeValue(el, value) {
  const previousValue = el.value;

  if (el.type === 'checkbox' || el.type === 'radio') {
    if ((!!value && !el.checked) || (!!!value && el.checked)) {
      el.click();
    }
  } else el.value = value;

  const tracker = el._valueTracker;
  if (tracker) {
    tracker.setValue(previousValue);
  }

  // 'change' instead of 'input', see https://github.com/facebook/react/issues/11488#issuecomment-381590324
  el.dispatchEvent(new Event('change', { bubbles: true }));
}
Run Code Online (Sandbox Code Playgroud)

用法:

setNativeValue(document.getElementById('name'), 'Your name');
document.getElementById('radio').click(); // or setNativeValue(document.getElementById('radio'), true)
document.getElementById('checkbox').click(); // or setNativeValue(document.getElementById('checkbox'), true)
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这适合我对使用 ReactJS 的自动完成和组合框字段的需求。:) (2认同)

Tim*_*imo 9

React正在侦听input文本字段的事件.

您可以更改值并手动触发输入事件,并且react的onChange处理程序将触发:

class Form extends React.Component {
  constructor(props) {
    super(props)
    this.state = {value: ''}
  }
  
  handleChange(e) {
    this.setState({value: e.target.value})
    console.log('State updated to ', e.target.value);
  }
  
  render() {
    return (
      <div>
        <input
          id='textfield'
          value={this.state.value}
          onChange={this.handleChange.bind(this)}
        />
        <p>{this.state.value}</p>
      </div>      
    )
  }
}

ReactDOM.render(
  <Form />,
  document.getElementById('app')
)

document.getElementById('textfield').value = 'foo'
const event = new Event('input', { bubbles: true })
document.getElementById('textfield').dispatchEvent(event)
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'></div>
Run Code Online (Sandbox Code Playgroud)


mer*_*ial 9

由于重复数据删除输入和更改事件的更改,该已接受的解决方案在React> 15.6(包括React 16)中似乎不起作用。

您可以在此处查看React讨论:https : //github.com/facebook/react/issues/10135

以及此处建议的解决方法:https : //github.com/facebook/react/issues/10135#issuecomment-314441175

为方便起见,此处转载:

代替

input.value = 'foo';
input.dispatchEvent(new Event('input', {bubbles: true}));
Run Code Online (Sandbox Code Playgroud)

你会用

function setNativeValue(element, value) {
  const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
  const prototype = Object.getPrototypeOf(element);
  const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;

  if (valueSetter && valueSetter !== prototypeValueSetter) {
    prototypeValueSetter.call(element, value);
  } else {
    valueSetter.call(element, value);
  }
}
Run Code Online (Sandbox Code Playgroud)

然后

setNativeValue(input, 'foo');
input.dispatchEvent(new Event('input', { bubbles: true }));
Run Code Online (Sandbox Code Playgroud)

  • 这在greasemonkey中对我不起作用 - 可能是关于安全性的问题......甚至只是尝试调用`Object.getOwnPropertyDescriptor(..)`也失败了。对我来说,使用 /sf/answers/3674084501/ 中的 `setNativeValue(..)` 函数在 Greasemonkey 中工作。 (2认同)

alj*_*gom 7

我注意到输入元素有一些名称类似于 的属性__reactEventHandlers$...,它有一些功能,包括onChange.

这有助于找到该功能并触发它

更新: __reactEventHandlers$...似乎已将名称更改为__reactProps$...,因此请在.filter下面尝试

let getReactEventHandlers = (element) => {
    // the name of the attribute changes, so we find it using a match.
    // It's something like `element.__reactEventHandlers$...`
    let reactEventHandlersName = Object.keys(element)
       .filter(key => key.match('reactEventHandler'));
    return element[reactEventHandlersName];
}

let triggerReactOnChangeEvent = (element) => {
    let ev = new Event('change');
    // workaround to set the event target, because `ev.target = element` doesn't work
    Object.defineProperty(ev, 'target', {writable: false, value: element});
    getReactEventHandlers(element).onChange(ev);
}

input.value = "some value";
triggerReactOnChangeEvent(input);
Run Code Online (Sandbox Code Playgroud)