一、場景
在開發過程中,會使用很多的Select、DatePicker等組件,當這些組件在可滾動的區域內滾動時,你會發現該組件的選項框也會跟着滾動,產生分離。如下圖所示。
二、解決方法
通過查詢相應的官方API,發現官方給我們提供了getPopupContainer屬性,該屬性是菜單渲染的父節點,默認是body。只要添加該屬性,設置好父節點,就可以解決這種分離。
添加getPopupContainer屬性
getPopupContainer={(triggerNode: any) => triggerNode.parentNode}
在Select、DatePicker、Cascader添加getPopupContainer屬性栗子:
<div style={{ margin: 10, overflow: 'scroll', height: 500 }}> <div style={{ padding: 100, height: 1000 }} id='getPopupContainerDiv'> <Select defaultValue="1" style={{ width: 120 }} getPopupContainer={(triggerNode: any) => triggerNode.parentNode} > <Option value="1">選項1</Option> <Option value="2">選項2</Option> </Select> <DatePicker getPopupContainer={(triggerNode: any) => triggerNode.parentNode} style={{ width: '160px' }} format="YYYY-MM-DD" /> <Cascader getPopupContainer={(triggerNode: any) => triggerNode.parentNode} options={options} /> </div> </div>
設置完成之后,發現Select是沒有分離的,但是DatePicker和Cascader還是會分離。
這是為什么呢?首先看了一下版本,我的antd版本是4.x的,在3.x是正常的,這就讓人掉頭發了。
沒辦法,先硬着頭皮打印一下這三個組件的triggerNode以及triggerNode.parentNode觀察一下。
Select的triggerNode以及triggerNode.parentNode
DatePicker和Cascader的triggerNode以及triggerNode.parentNode
果真,三個組件的triggerNode.parentNode有差異,DatePicker和Cascader直接找到了最外層的div,他的節點還是在最外層,導致分離。
原因找到了,如何解決呢?
既然官方提供的是定位到父節點,就可以解決分離問題,那么我直接定位到本身節點,那豈不是也可以解決?將getPopupContainer代碼修改一番,如下:
getPopupContainer={(triggerNode: any) => triggerNode}
結果:修改完之后運行,發現都不再分離。
三、全局設置getPopupContainer
一般來說,項目中會用到很多這種選擇組件,我們如果一個一個的去添加getPopupContainer屬性,那么久太麻煩了,這就需要我們全局配置。
<ConfigProvider
locale={zh_CN}
getPopupContainer={(node: any) => node} //ant 4.x
// getPopupContainer={(triggerNode: any) => triggerNode.parentNode} //ant 3.x
<Route />
</ConfigProvider >
這樣配置完成之后,全局就配置完畢,不需要我們每個都去添加。
四、全局配置后,在Modal中使用報錯解決
開發項目,肯定會使用Modal彈框組件,在Modal組件中也避免不了使用選擇組件,在全局配置完getPopupContainer后,發現Modal會報錯。
ant3.x版本報錯,4.x版本直接空白
官方API給的解釋是:全局設置getPopupContainer
觸發節點時,Modal 的用法不存在 triggerNode導致報錯
解決方法:增加一個判斷條件
<ConfigProvider
locale={zh_CN}
//getPopupContainer={(node: any) => node}
getPopupContainer={(node: any) => {
if (node) {
return node //ant 4.x
// return node.parentNode; //ant 3.x
} return document.body;
}}
>
<Route />
</ConfigProvider >
五、完整代碼

import React from 'react'; import { Button, Select, DatePicker, Cascader, Modal, Form } from 'antd' const Option = Select.Option export default () => { const [form] = Form.useForm(); const options = [ { value: 'zhejiang', label: 'Zhejiang', children: [ { value: 'hangzhou', label: 'Hangzhou', children: [ { value: 'xihu', label: 'West Lake', }, ], }, ], }, { value: 'jiangsu', label: 'Jiangsu', children: [ { value: 'nanjing', label: 'Nanjing', children: [ { value: 'zhonghuamen', label: 'Zhong Hua Men', }, ], }, ], }, ]; const triggerNodeFunc = (triggerNode: any) => { console.log(triggerNode) console.log(triggerNode.parentNode) return triggerNode } return ( <div> <Modal title='組件選項框滾動分離' visible={true} bodyStyle={ { maxHeight: '300px', overflowY: 'auto' } } > <div style={{ padding: 100, height: 1000 }}> <Select defaultValue="1" style={{ width: 120 }} > <Option value="1">選項1</Option> <Option value="2">選項2</Option> </Select> <DatePicker style={{ width: '160px' }} format="YYYY-MM-DD" /> <Cascader options={options} /> </div> </Modal> {/* <div style={{ margin: 10, overflow: 'scroll', height: 500 }}> <div style={{ padding: 100, height: 1000 }} id='getPopupContainerDiv'> <Select defaultValue="1" style={{ width: 120 }} // getPopupContainer={(triggerNode: any) => triggerNodeFunc(triggerNode)} > <Option value="1">選項1</Option> <Option value="2">選項2</Option> </Select> <DatePicker // getPopupContainer={(triggerNode: any) => triggerNode} style={{ width: '160px' }} format="YYYY-MM-DD" /> <Cascader // getPopupContainer={(triggerNode: any) => triggerNodeFunc(triggerNode)} options={options} /> </div> </div> */} </div > ); }

ReactDOM.render( <Provider store={store}> <ConfigProvider locale={zh_CN} // getPopupContainer={(node: any) => node} // getPopupContainer={(triggerNode: any) => triggerNode.parentNode} getPopupContainer={(node: any) => { if (node) { return node // return node.parentNode; } return document.body; }} > <Route /> </ConfigProvider > </Provider>, document.getElementById('root') );