问题原因
在网上寻求解决方法时看到了很多次
antd Select组件的allowClear点击失效 无法清空? 观察发现,由于同时设置了value属性和allowClear属性, 导致无法点击清空按钮清空当前选中项,官方相应的文档并没有提供allowClear点击事件让我们订制自己的事件,因此,解决办法是去除value或者获取到清空按钮的dom元素,增加点击事件.
So. 既然我们写了value属性那想必绑定事件对我们来说是更好地选择
解决思路
如上文提到的获取dom元素->添加点击事件 虽然看起来很简单,但我在实践过程遇到了一些问题,因为值得总结一波。
要拿元素就要先找到ta console一波
onMouseEnter={this.handleMouseenter}
handleMouseenter = (e)=>{
console.log(e)
}
打印结果
啧. 不对劲 这target为啥空的呀 不说了 百度!
React 的 on 开头的事件都是合成事件,不是真实的,在原生的 DOM 上进行了封装,封装好之后交给事件池进行管理,合成事件对象可能会被重用,合成事件的所有属性也会随之被清空。所以当在异步处理程序(如 setTimeout 等等)中或者浏览器控制台中去访问合成事件的属性,默认 react 会把其属性全部设为 null 。
所以如果想要在 react 中想异步访问事件属性(如在 setTimeout 内),应该在是处理事件时调用 event.persist()或者我们命名的名称e.persist() ,这会从事件池中移除该合成函数并允许对该合成事件的引用被保留下来。
虽然成功打印了,但是也随之出现了新的问题当我们从Select下侧滑入时会先访问到右侧的dom,我们暂时称它为rendered,而当从其他位置使用鼠标滑入时则会打印左侧的dom,我们暂时称它为single,而根据我们的dom结构来看,rendered是single的子元素, 而我们需要获取的是rendered下面的那个兄弟节点clear,
接下来我们直接上代码
handleMouseenter = (e)=>{
//控制台打印或异步处理时需要此函数
e.persist()
console.log(e)
//非下侧滑入时
let selectSingle = e.target.children[1];
//下侧滑入时
let selectRender = e.target.parentElement.children[1];
//如果当前的dom中不包含clear则不应该执行(我在此处通过select的placeholder判断的)
if( e.target.outerText != 'placeholder'){
//接下来就通过三元表达式来判断是使用selectSingle还是selectRender去找到clear这个元素
let selectClear = selectSingle.className == 'ant-select-selection__clear'
?selectSingle
:(selectRender.className == 'ant-select-selection__clear' ? selectRender:null)
//获取到dom元素后添加事件就可以了
selectClear.addEventListener('click',()=>{
//因为我的select中设置了placeholder属性,所以需要将value绑定的值设置为undefined才能使placeholder生效
this.setState({rulesetsCurrentId :undefined})
console.log('清除成功')//重复滑入会导致触发多次,详情请看下文。
})
}
}
如果进行大量内存引用的操作的话就需要在组件卸载时进行事件解绑
下面是一个在网上看到的只生效一次的写法,这个方法很适合我们上面用到的onMouseEnter事件(频繁的滑入操作)
el.addEventListener('click', function a(){
//do sth
this.removeEventListener('click', a)
})
还有一篇文章是关于解决事件重复绑定这个问题的 stackoverflow因为不是问题讨论范围,就简单贴个链接吧。 帅哥美女们看到这儿了不点个赞再走吗 嘿嘿。