使用了antd-mobile的Picker造成点击事件多次触发
需求
页面上一个显示温度的div(<div className="tem">
下称 .tem),点击时弹框,通过弹框修改这个温度的数据。
环境
使用 react hooks + antd-mobile,弹框使用 Picker 组件
实现
显示温度的div如下,其中的子组件<TemPicker >
封装了Picker组件。当 .tem 被点击时,手动通过触发这个隐藏的 .itemForPicker 的点击事件来实现弹出。
……
const temPickerBar = useRef(null)
// 显示温度的点击事件
const temPickerClick = ({ target }) => {
console.log('~~点击温度了', target)
if (temPickerBar.current) {
temPickerBar.current.click()
}
}
……
// 显示温度的div
<div className='tem' onClick={temPickerClick}>
<div className='value'>{temPickerVal}℃</div>
<div className='text'>设定温度<i className='iconfont i-arrow_right' /></div>
{currMode?.tem && temPickerVal &&
<TemPicker tem={currMode.tem[0]} setTemVal={setTemVal} value={[temPickerVal]} pickerBar={temPickerBar} />
}
</div>
// 子组件的jsx结构
<Picker data={[data]} value={[Number(value)]} onChange={v => setTemVal(v[0])} >
<div className='itemForPicker' ref={pickerBar} style={{ display: pickerBar ? 'none' : 'flex' }}>
<span className='content'>烹饪温度</span>
<span className='extra'>{value + '℃'}</span>
<i className='iconfont i-arrow_right' />
</div>
</Picker>
问题
点击一次元素 .tem 时,框是弹出来了,也能隐藏。操作看起来一切正常,但通过打印发现点击事件共执行了4次,其中点击元素.time的瞬间触发2次,然后隐藏弹框时又触发2次,而我只需要点开时触发一次。
解决
- 查得每点击一次会触发2次事件的原因是item元素冒泡导致,在Picker的子元素上添加阻止冒泡事件即可解决,每次点击就会只触发一次。
- 每次隐藏弹框时自动触发的点击事件来源不明,又没找到阻断事件传播源的方法,最后的解决方案是:在点击事件传进来时,通过判断事件的目标元素中不包含 .tem 或其子元素来确认点击事件是被动触发的,从而阻止。
if (![target?.className, target?.parentElement?.className].includes('tem')) return
点击事件的完整代码:
const temPickerClick = ({ target }) => {
// 由于弹窗关闭时会自动触发到这里来,造成不必要的点击事件,所以判断一下,如果不是手动点击的事件就屏蔽掉。
if (![target?.className, target?.parentElement?.className].includes('tem')) return
console.log('~~点击温度了', target)
if (temPickerBar.current) {
temPickerBar.current.click()
}
}
注意:第二个解决方法已经覆盖了第一种,所以无需两种都写。