关于Affix组件在抽屉中不生效的解决

2020-07-02  本文已影响0人  penelope_2bad
  1. antd 3.x版本的Affix在抽屉组件中不生效
  2. 可以利用sticky来做
    1. 在目标元素中声明:position: 'sticky', top: '0'
    2. 目标元素的父元素上不能有:visible: hidden属性
      设置抽屉下.ant-tabs属性为:overflow: visible !important;
  3. 利用js原生代码结合React.useLayoutEffect, React.useRef来做
    1. 通过React.useRef获取到真实dom元素
  const paneRef = React.useRef<{
    question: HTMLDivElement;
    service: HTMLDivElement;
  }>({
    question: null,
    service: null,
  });

 <div
    ref={(ref) => {
        paneRef.current.question = ref;
    }}
  >
     <Alert
         type="info"
         message="此设置为质检、培训能力通用,请慎重修改哦"
         showIcon
     />
</div>
  1. 找到显示滚动条的元素
function findParentNode(className: string, sourceNode: HTMLElement) {
  let parent = sourceNode.parentElement;
  while (parent !== document.body) {
    if (parent.classList.contains(className)) {
      return parent;
    } else {
      parent = parent.parentElement;
    }
  }
  return null;
}
  1. 利用React.useLayoutEffect为显示滚动条元素绑定scroll事件

  React.useLayoutEffect(() => {
    let listenerNode;
    if (paneRef.current[TabType[tabType]]) {
      listenerNode = findParentNode(
        'ant-drawer-wrapper-body',
        paneRef.current[TabType[tabType]]
      );
      listenerNode.addEventListener('scroll', throttle(handleAffix, TabType[tabType], 20));
    }
    return () => {
      listenerNode.addEventListener('scroll', throttle(handleAffix, TabType[tabType], 20));
    }
  }, [tabType]);
  1. 利用原生js实现目标元素affix效果
   const handleAffix = (type) => {
    const parent = paneRef.current[type];
    if (parent.getBoundingClientRect().top < 0) {
      const child = parent.children[0];
      child.classList.add('affix');
    } else {
      const child = parent.children[0];
      child.classList.remove('affix');
    }
  };
  1. 加一层函数的节流, 大功告成
  const throttle = (fn, type, delay) => {
    let prev = Date.now();
    return function () {
      const context = this;
      const now = Date.now();
      if (now - prev >= delay) {
        fn.apply(context, [type]);
        prev = Date.now();
      }
    };
  };

  1. 全部代码

import * as React from 'react';
import { Tabs, Alert } from 'antd';

import TreeEditor from './TreeEditor';

import { ServiceType } from '../../services/types';

const { TabPane } = Tabs;

enum TabType {
  question,
  service,
}

function findParentNode(className: string, sourceNode: HTMLElement) {
  let parent = sourceNode.parentElement;
  while (parent !== document.body) {
    if (parent.classList.contains(className)) {
      return parent;
    } else {
      parent = parent.parentElement;
    }
  }
  return null;
}

export interface ServiceRulesProps {
  onChange?: () => void;
  activeKey?: ServiceType;
}

export const ServiceRules: React.FC<ServiceRulesProps> = (props) => {
  const { onChange, activeKey } = props;
  const paneRef = React.useRef<{
    question: HTMLDivElement;
    service: HTMLDivElement;
  }>({
    question: null,
    service: null,
  });

  const handleChange = () => {
    onChange && onChange();
  };

  const [tabType, setTabType] = React.useState(TabType.question);

  React.useLayoutEffect(() => {
    let listenerNode;
    if (paneRef.current[TabType[tabType]]) {
      listenerNode = findParentNode(
        'ant-drawer-wrapper-body',
        paneRef.current[TabType[tabType]]
      );
      listenerNode.addEventListener('scroll', throttle(handleAffix, TabType[tabType], 20));
    }
    return () => {
      listenerNode.addEventListener('scroll', throttle(handleAffix, TabType[tabType], 20));
    }
  }, [tabType]);

  const handleAffix = (type) => {
    const parent = paneRef.current[type];
    if (parent.getBoundingClientRect().top < 0) {
      const child = parent.children[0];
      child.classList.add('affix');
    } else {
      const child = parent.children[0];
      child.classList.remove('affix');
    }
  };

  const throttle = (fn, type, delay) => {
    let prev = Date.now();
    return function () {
      const context = this;
      const now = Date.now();
      if (now - prev >= delay) {
        fn.apply(context, [type]);
        prev = Date.now();
      }
    };
  };

  const handleTabChange = (key) => {
    setTabType(key);
  };

  return (
    <Tabs
      defaultActiveKey={String(activeKey)}
      tabBarStyle={{ padding: '5px 24px 0 24px', margin: 0 }}
      onChange={handleTabChange}
    >
      <TabPane className="tab-container" tab="服务问题" key="0">
        <div
          ref={(ref) => {
            paneRef.current.question = ref;
          }}
        >
          <Alert
            type="info"
            message="此设置为质检、培训能力通用,请慎重修改哦"
            showIcon
          />
        </div>
        <TreeEditor
          onChange={handleChange}
          serviceType={ServiceType.disadvantages}
          style={{ marginTop: 18 }}
        />
      </TabPane>
      <TabPane className="tab-container" tab="服务亮点" key="1">
        <div
          ref={(ref) => {
            paneRef.current.service = ref;
          }}
        >
          <Alert
            type="info"
            message="此设置为质检、培训能力通用,请慎重修改哦"
            showIcon
          />
        </div>
        <TreeEditor
          onChange={handleChange}
          serviceType={ServiceType.advantages}
          style={{ marginTop: 18 }}
        />
      </TabPane>
    </Tabs>
  );
};

ServiceRules.defaultProps = {
  activeKey: ServiceType.disadvantages,
};

上一篇 下一篇

猜你喜欢

热点阅读