antd的Select,DatePicker,Cascader等组件选项框随页面滚动的问题解决

一、场景

  在开发过程中,会使用很多的Select、DatePicker等组件,当这些组件在可滚动的区域内滚动时,你会发现该组件的选项框也会跟着滚动,产生分离。如下图所示。

 

二、解决方法

  通过查询相应的官方API,发现官方给我们提供了getPopupContainer属性,该属性是菜单渲染的父节点,默认是body。只要添加该属性,设置好父节点,就可以解决这种分离。

  添加getPopupContainer属性

getPopupContainer={(triggerNode: any) => triggerNode.parentNode}
  triggerNode:当前元素的节点
  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')
);
全局配置代码

 

posted @ 2020-06-04 20:00  MinorF_γ  阅读(4104)  评论(0编辑  收藏  举报