前言
事实证明radix-ui的生态还有待提升啊……我以为这是个比较常见的问题。
在github的discussions里有看到类似的问题(相关的github disscussions),只是开发者承诺的解决到现在还没有消息。
只能自己改了,希望后面的版本有组件上的支持吧,现在只能自己改了。希望给同样遇到这个问题的人一点帮助。
现象
事情是这样的,我在自己制作一个编辑器时,有这样一个需求:
正常情况下,代码块上方的切换语言等工具栏应该是隐藏的;在鼠标悬浮到代码块上时才会显示。
那当然这种情况下不只是我鼠标放在代码块上需要它显示,我放到下拉框上也得让它保持不消失吧?
这很简单,我给整个组件加一个mouseenter事件等等进行管理就是了……
但是!在我用hover进行管理的时候,发现在下拉框打开的时候,页面上的其他鼠标事件都被屏蔽掉了,不只是这里的hover,你还会发现你自己设置的各种鼠标样式都不生效了,除了这个下拉框之外的所有区域都是这样。
这还玩个der?!
问题分析
当然,很容易就能发现原因,是因为radix内部有套逻辑,在打开portal的时候,它会默认给你的body上加一个pointer-events: none,这个属性的效果不清楚的直接上mdn看吧不解释了。
其实radix是有想到这一点的,前面也说了他们本来计划的是要改只是没改而已,我前面还用过他们的DropdownMenu组件,它提供了modal属性可以解决这个问题。但是不知道为啥搁置了……
解决方案
说了一大堆,解决方案其实很简单,给它body上的这个属性去掉就是了,这里提供一个hook吧:
const useRadixFix = () => {
useEffect(() => {
const observer = new MutationObserver(() => {
if (getComputedStyle(document.body).pointerEvents === 'none') {
document.body.style.removeProperty('pointer-events')
}
})
observer.observe(document.body, { attributes: true })
return () => observer.disconnect()
}, [])
}
这里配合@radix-ui/react-select的使用可以看下我的实现(组件的其他细节略):
// 略
const [open, setOpen] = useState(false);
useEffect(() => {
const observer = new MutationObserver(() => {
if (getComputedStyle(document.body).pointerEvents === 'none') {
document.body.style.removeProperty('pointer-events');
}
});
if (open) {
observer.observe(document.body, { attributes: true });
} else {
console.log('disconnecting');
observer.disconnect();
}
return () => observer.disconnect();
}, [open]);
return <Select.Root open={open} onOpenChange={setOpen} onValueChange={onChange}>...内部实现略</Select.Root>
最后必须说一下,这种解决方案是很拙劣的,属于是没办法的方案,写了之后可能所有组件都会受到影响(或许有方法束缚,但是也并不优雅),总之还是希望官方早点出组件上的解决吧,遇到问题的也可以去催一催。
后面我可能还会继续使用radix-ui,遇到一些问题也会陆续提出来,有些可能有自己的解决方法有些则依赖大家一起想方法了,有相关需求的请关注我,对radix、tiptap这块有兴趣的也可以多多交流。
That's end