• 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={{  120 }}
                getPopupContainer={(triggerNode: any) => triggerNode.parentNode}
              >
                <Option value="1">选项1</Option>
                <Option value="2">选项2</Option>
              </Select>
    
              <DatePicker
                getPopupContainer={(triggerNode: any) => triggerNode.parentNode}
                style={{  '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={{  120 }}
              >
                <Option value="1">选项1</Option>
                <Option value="2">选项2</Option>
              </Select>
    
              <DatePicker
                style={{  '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={{  120 }}
              // getPopupContainer={(triggerNode: any) => triggerNodeFunc(triggerNode)}
              >
                <Option value="1">选项1</Option>
                <Option value="2">选项2</Option>
              </Select>
    
              <DatePicker
                // getPopupContainer={(triggerNode: any) => triggerNode}
                style={{  '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')
    );
    全局配置代码
  • 相关阅读:
    documentFragment文档碎片
    OpenResty之resty.limit.count 模块介绍
    vue前端分页多条件搜索
    element ui Tree树形控件获取未全选父节点和子节点id
    如何使 pdf 文件在浏览器里面直接下载而不是打开
    关于本博客
    圆锥曲线基础知识点
    NOI2021游记
    20210716模拟赛
    计数+动态规划
  • 原文地址:https://www.cnblogs.com/minorf/p/13039683.html
Copyright © 2020-2023  润新知