【问题标题】:React custom checkbox => trigger 'change' event反应自定义复选框 => 触发“更改”事件
【发布时间】:2021-09-23 19:30:19
【问题描述】:

我用普通的div/span 制作了a custom checkbox control

因为<input type='checkbox'.../> 不能有子元素,所以我用divrole='checkbox'aria-checked={isChecked} 创建了另一个元素。
然后我处理了切换检查状态的鼠标和键盘事件。

问题是:
如何触发'change'事件?下面的代码在 react 16 中不起作用

refTarget?.current?.dispatchEvent(new Event('change', { bubbles: true, cancelable: false }))

另一个技巧是直接调用props.onChange
它有效,但事件不会冒泡到父 <form onChange={(e) => console.log('changed!')}></form>

【问题讨论】:

    标签: reactjs dom-events custom-controls


    【解决方案1】:

    您有 2 种方法可以实现这一目标。

    1.动态创建所有事件。

    eventTarget.dispatchEvent 在 React 中不起作用。查看this question 了解替代方法和更多信息。

    2.从输入接收 onChange 事件

    您可以接收通过不透明度隐藏真正的input 元素,并使其跨越元素的整个宽度/高度。那么你只需要在这个input上听onChange

    material-ui 就是这样做的

    例子

    const { useCallback, useState, useRef } = React;
    
    const MyCheckBox = React.forwardRef((props, ref) => {
      const { onChange, onBlur, onFocus, ...otherProps } = props;
      
      const [checked, setChecked] = useState(false);
      
      const handleFocus = useCallback((e) => {
        // do something,
        // like add some className for effects
        if (typeof onFocus === 'function')
          onFocus(e)
      }, [])
      const handleBlur = useCallback((e) => {
        // do something,
        // like remove some className for effects
        if (typeof onBlur === 'function')
          onBlur(e)
      }, [])
      
      const handleChange = useCallback((e) => {
        setChecked(e.target.checked);
        if (typeof onChange=== 'function')
          onChange(e)
      }, []);
      
      return <div onFocus={handleFocus} onBlur={handleBlur} className="checkbox-root">
      {checked ? 'Checked' : 'Not checked'}
        <input onChange={handleChange} ref={ref} type="checkbox" className="checkbox-input" {...otherProps} />
      </div>
    })
    
    const App = (props) => {
     return <div>
     <MyCheckBox onChange={e => console.log('change', e.target.checked)} onFocus={e => console.log('focus')} onBlur={e => console.log('blur')} />
     </div>;
    }
    
    ReactDOM.render(<App />, document.querySelector('#root'))
    .checkbox-root {
      position: relative;
      height: 40px;
      width: 40px;
      border: 1px solid red;
    }
    .checkbox-input {
      position: absolute;
      opacity: 0.1;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      width: 100%;
      height: 100%;
      margin: 0;
    }
    
    .hidden-input {
      display: none;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.production.min.js"></script>
    
    <div id="root"/>

    【讨论】:

    • 但是分层透明的真实输入会导致父元素失去焦点。该元素上已有焦点/模糊指示。
    • 如果从 vanilla js addEventListener 监听,自定义事件有效,但在 React 的 onChange={ } 上无效。适用于 react v15 但不适用于 v16
    • @HeyyyMarco 更新了答案。 dispatchEvent 在反应中不起作用。您可以阅读随附的问题以获取更多信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-03
    • 1970-01-01
    • 1970-01-01
    • 2014-03-21
    • 2010-10-30
    • 1970-01-01
    相关资源
    最近更新 更多