【问题标题】:React onChange on radio button fires onClick on parent div element对单选按钮做出反应 onChange 在父 div 元素上触发 onClick
【发布时间】:2017-06-02 08:47:35
【问题描述】:

我希望通过键盘处理更改与通过鼠标单击进行更改不同。为此,我创建了以下组件。我的问题是,当我使用箭头键和空格来选择单选按钮时,它先使用父 div 元素中的 onClick 方法,然后再使用输入元素中的 onChange 方法。这种行为的原因是什么,如何正确处理?

class Radio extends React.Component {
  constructor(props) {
    super(props);

    this.onChange = this.onChange.bind(this);
    this.onClick = this.onClick.bind(this);

    this.state = { checked: false };
  }

  onChange() {
    this.setState({ checked: !this.state.checked });
    console.log('onChange');
  }

  onClick() {
    this.onChange();
    console.log('onClick');
  }

  render() {
    return (
      <div onClick={this.onClick}>
        <input
          type="radio"
          checked={this.state.checked}
          onChange={this.onChange}
        />
        Click me!
      </div>
    );
  }
}

ReactDOM.render(<Radio />, document.getElementById('root'));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react-dom.min.js"></script>

【问题讨论】:

    标签: javascript html reactjs


    【解决方案1】:

    正如在this issueW3C documentation 的这一部分中看到的,这似乎是一种默认的浏览器行为。

    当用户以非点击方式触发具有已定义激活行为的元素时,交互事件的默认操作必须是在该元素上运行合成点击激活步骤。

    要解决此问题,请在您的 onClick 处理程序中添加以下逻辑:

    if (e.type === 'click' && e.clientX !== 0 && e.clientY !== 0) {
      // This is a real click. Do something here
    }
    

    感谢 GitHub 用户 Ro Savage 指出这一点。


    这是一个完整的演示:

    class Radio extends React.Component {
      constructor(props) {
        super(props);
    
        this.onChange = this.onChange.bind(this);
        this.onClick = this.onClick.bind(this);
    
        this.state = { checked: false };
      }
    
      onChange() {
        this.setState({ checked: !this.state.checked });
        console.log('onChange');
      }
    
      onClick(e) {
        if (e.type === 'click' && e.clientX !== 0 && e.clientY !== 0) {
          this.onChange();
          console.log('onClick');
        } else {
          console.log('prevented "onClick" on keypress');
        }
      }
    
      render() {
        return (
          <div onClick={this.onClick}>
            <input
              type="radio"
              checked={this.state.checked}
              onChange={this.onChange}
            />
            Click me!
          </div>
        );
      }
    }
    
    ReactDOM.render(<Radio />, document.getElementById('root'));
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react-dom.min.js"></script>

    【讨论】:

    • 非常有趣!您的解决方案效果很好,谢谢。
    【解决方案2】:

    您可以禁用点击事件的传播:

    <input
        type="radio"
        checked={this.state.checked}
        onClick={(e)=>{e.stopPropagation()}}
        onChange={this.onChange}
    />
    

    【讨论】:

    • 感谢您的回答。这个解决方案的问题是,在使用键盘时,单选按钮没有得到视觉检查。有没有办法解决这个问题?
    【解决方案3】:

    事件的顺序很重要:click 事件将在 change 事件之前触发。 由于事件冒泡,父元素的onClick-handler 将在子元素的onChange-handler 之前触发。

    要解决您的特定问题,例如,您可以在 container-div 上收听 keydown-event。此事件应在单击或更改事件之前触发。

    class Radio extends React.Component {
      constructor(props) {
        super(props);
    
        this.onChange = this.onChange.bind(this);
        this.onKeyUp = this.onKeyUp.bind(this);
    
        this.state = { checked: false };
      }
    
      onChange() {
        this.setState({ checked: !this.state.checked });
        console.log('onChange');
      }
    
      onKeyUp() {
        console.log('onKeyUp');
        this.onChange();
      }
    
      render() {
        return (
          <div onKeyUp={this.onKeyUp}>
            <input
              type="radio"
              checked={this.state.checked}
              onChange={this.onChange}
            />
            Click me!
          </div>
        );
      }
    }
    
    ReactDOM.render(<Radio />, document.getElementById('root'));
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react-dom.min.js"></script>

    【讨论】:

      猜你喜欢
      • 2018-05-07
      • 1970-01-01
      • 2016-09-12
      • 1970-01-01
      • 2017-09-10
      • 1970-01-01
      • 2019-05-27
      • 2019-02-23
      • 1970-01-01
      相关资源
      最近更新 更多