看一看antd 中 select/dropdown 等组件的下拉框

吐槽君 分类:javascript

背景:在项目中使用 select 组件,点击 select 出现下拉框的状态时,滑动页面下拉框不跟随 select 组件滑动。也就是不固定在 select 组件的下方。
于是开始思考:
antd 是怎么实现下拉框的?下拉框跟随滚动是怎么做的?

先说解决办法吧:

查看API文档:

getPopupContainer: 菜单(下拉框哈)渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。

getPopupContainer 接受一个函数作为参数,函数执行时会接受一个组件传给他的参数 triggerNode,返回菜单渲染的父节点。
所以可以设置:

getPopupContainer={(triggerNode) => triggerNode.parentNode}
 

这时候菜单渲染的父节点就是 antd 的 select 组件。
当然你可以设置为其他任意的节点为下拉框的父节点。但需要注意的是,下拉框是绝对定位的,要使滑动生效的话,最好父节点设置为相对定位(绝对定位也可,只是要注意与父节点同级的元素的位置关系)。否则下拉框会继续向上寻找定位不为 static 的元素,有可能就找到了 document.body 。起不到吸附的作用。

实现下拉组件的原理解析

在不设置 getPopupContainer 属性的时候,默认当第一次触发下拉框组件时,会在 body 节点下生成一个绝对定位的 div(下拉框的父节点):

image.png

当触发出现下拉框时(下拉框):

image.png

会根据 triggerNode 和 body 来计算 left 和 top 的值:(=offsetTop/offsetLeft/offsetHeight/offsetWidth

下拉框父节点一旦生成之后即使收起下拉框,也不会卸载这个节点(回流重绘好费性能的说!)。也就是说下拉框的父节点的位置就确定了,每次计算出来的下拉框的 left/right 也就确定了。
因此当 select 组件所在的可滑动区域和 document.body 分开时,就会出现上面说的情况。下拉框不吸附。
这时候只要找到一个相对于 select 组件一起滑动的父组件(相对位置不变),将他作为下拉框组件的父组件即可。

情况1. 也可以将下拉框组件放在select组件下:

getPopupContainer={(triggerNode) => triggerNode.parentNode}
 

image.png

.ant-select:{position:relative,...}

情况2. 放在相对于 select 组件一起滑动的父组件下,难点需要分析找到这个父组件。

image.png

这里就选择了 #mainContent作为父节点,#rootContent 设置 height 为100%,#rootContent 的高度就不随内容改变,因此 body 与 select 的相对位置时变化的,所以不能选择 body,又因为所有 react_grid_item 都为绝对定位元素。select 所在的父元素高度为 32px,如果设置

getPopupContainer={(triggerNode) => triggerNode.parentNode}
 

则弹出的下拉框会被下一个 absolute 的 react_grid_item 元素挡住。

学到了什么

可以借鉴这种方法实现带有下拉框的组件,确定父组件,生成一个元素来确定下拉框的位置。

回复

我来回复
  • 暂无回复内容