反应自定义复选框 => 触发“更改”事件

时间:2021-07-14 20:11:52

标签: reactjs dom-events custom-controls

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

因为 <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>

1 个答案:

答案 0 :(得分:0)

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

1.动态创建所有事件。

eventTarget.dispatchEvent 在 React 中不起作用。检查 this question 以获取替代方法和更多信息。

2.从输入接收 onChange 事件

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

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"/>

相关问题