React-Component-Library--Affix

Affix 固钉

使用以及文档如图:

封装代码如下所示 

import React, { FC, memo, useEffect, useState } from 'react';
import './index.module.less';

interface AffixProps {
  /**
   * @description 类型 scroll表示滚动容器
   * @default ''
   */
  affixType?: string;
  /**
   * @description 插槽
   */
  children?: any;
  /**
   * @description 顶部距离
   * @default 0
   */
  offsetTop?: number | string;
  /**
   * @description 左侧距离
   * @default 0
   */
  offsetLeft?: number | string;
  /**
   * @description 底部距离
   * @default 0
   */
  offsetBottom?: number | string;
  /**
   * @description 右侧距离
   * @default 0
   */
  offsetRight?: number | string;
  /**
   * @description 插槽样式
   * @default {}
   */
  style?: Object;
}
interface offsetProps {
  left?: number | string;
  right?: number | string;
  top?: number | string;
  bottom?: number | string;
  position?: string;
}
const Affix: FC<AffixProps> = (props) => {
  const { children, affixType, offsetTop, offsetLeft, offsetBottom, offsetRight, style } = props;

  const [affixElOffset, setAffixElOffset] = useState<offsetProps>({});
  let io: IntersectionObserver; //观察者

  useEffect(() => {
    const el = document.querySelector('.affix') as Element;
    io = new IntersectionObserver((entries) => elementObverse(entries));
    io.observe(el); //数据劫持监听
    if (affixType == 'scroll') {
      window.addEventListener('scroll', screenScroll);
      setAffixElOffset((old) => {
        old.position = 'relative';
        if (offsetTop && !old.bottom) {
          old.top = 0;
        }
        if (offsetBottom && !old.top) {
          old.bottom = 0;
        }
        if (offsetLeft && !old.right) {
          old.left = 0;
        }
        if (offsetRight && !old.left) {
          old.right = 0;
        }
        return JSON.parse(JSON.stringify(old));
      });
    } else {
      setAffixElOffset((old) => {
        old.position = 'fixed';
        if (offsetTop && !old.bottom) {
          old.top = offsetTop;
        }
        if (offsetBottom && !old.top) {
          old.bottom = offsetBottom;
        }
        if (offsetLeft && !old.right) {
          old.left = offsetLeft;
        }
        if (offsetRight && !old.left) {
          old.right = offsetRight;
        }
        return JSON.parse(JSON.stringify(old));
      });
    }
    return () => {
      io.unobserve(el);
    };
  }, []);
  const screenScroll = () => {
    const el: any = document.querySelector('.affix');
    if (window.scrollY < 200) {
      //首屏时,无需脱离文档流
      setAffixElOffset((old: offsetProps) => {
        for (const key in old as offsetProps) {
          if (key == 'position') {
            old[key] = 'relative';
          } else if (key == 'right' || key == 'left' || key == 'top' || key == 'bottom') {
            old[key] = '0';
          }
        }
        return JSON.parse(JSON.stringify(old));
      });
    }
  };
  const elementObverse = (entries: Array<IntersectionObserverEntry>) => {
    //监听函数
    entries.forEach((entry: IntersectionObserverEntry) => {
      if (!entry.isIntersecting) {
        // 元素未被观测
        if (affixElOffset.position == 'relative') {
          setAffixElOffset((old) => {
            old.position = 'fixed';
            if (offsetTop && offsetTop !== old.top) {
              old.top = `${offsetTop}px`;
            }
            if (offsetBottom && offsetBottom !== old.bottom) {
              old.bottom = `${offsetBottom}px`;
            }
            if (offsetLeft && offsetLeft !== old.left) {
              old.left = `${offsetLeft}px`;
            }
            if (offsetRight && offsetRight !== old.right) {
              old.right = `${offsetRight}px`;
            }
            return JSON.parse(JSON.stringify(old));
          });
        }
      }
    });
  };

  return (
    <div
      className="affix"
      style={{ ...(affixElOffset as React.HtmlHTMLAttributes<any>), ...style }}
    >
      {children}
    </div>
  );
};

export default memo(Affix);

GitHub-address:

https://github.com/username-boy/react-component-library-view/icon-default.png?t=N5K3https://github.com/username-boy/react-component-library-view/

good  luck !

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值