All files / src/affix Affix.tsx

60% Statements 18/30
42.11% Branches 8/19
83.33% Functions 5/6
57.14% Lines 16/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102                                  1x                       2x     2x 2x 2x 2x       2x   2x                                                                     2x       2x 2x 2x 2x 2x 2x     2x                          
import React, {
  useRef,
  useState,
  useEffect,
  useMemo,
  forwardRef,
  useImperativeHandle,
} from "react";
import { AffixProps } from "./AffixProps";
import { getTarget, getRect, throttle, getFixed } from "./util";
import { addListener, removeListener } from "./AffixManager";
import { uuid } from "../_util/uuid";
 
export interface AffixHandles {
  update: () => void;
}
 
export const Affix = forwardRef(function Affix(
  {
    offsetTop,
    offsetBottom,
    target = window,
    children,
    style,
    className,
  }: AffixProps,
  ref: React.Ref<AffixHandles>
) {
  // 默认吸顶
  Iif (typeof offsetTop === "undefined" && typeof offsetBottom === "undefined") {
    offsetTop = 0; // eslint-disable-line no-param-reassign
  }
  const affixRef = useRef<HTMLDivElement>(null);
  const placeholderRef = useRef<HTMLDivElement>(null);
  const [affixStyle, setAffixStyle] = useState<React.CSSProperties>(undefined);
  const [placeholderStyle, setPlaceholderStyle] = useState<React.CSSProperties>(
    undefined
  );
 
  const update = useMemo(
    () =>
      throttle(() => {
        const placeholder = placeholderRef.current;
        if (!placeholder) {
          return;
        }
        const placeholderRect = getRect(placeholder);
        const sizeStyle = {
          width: placeholderRect.width,
          height: placeholderRect.height,
        };
 
        setPlaceholderStyle(sizeStyle);
 
        if (typeof offsetTop !== "undefined") {
          const top = getFixed(target, placeholder, offsetTop);
          setAffixStyle(
            typeof top !== "undefined"
              ? Object.assign({ position: "fixed", zIndex: 10, top }, sizeStyle)
              : undefined
          );
        } else {
          const bottom = getFixed(target, placeholder, offsetBottom, false);
          setAffixStyle(
            typeof bottom !== "undefined"
              ? Object.assign(
                  { position: "fixed", zIndex: 10, bottom },
                  sizeStyle
                )
              : undefined
          );
        }
      }),
    [offsetBottom, offsetTop, target]
  );
 
  useImperativeHandle(ref, () => ({
    update,
  }));
 
  useEffect(() => {
    update();
    const id = uuid();
    const targetElement = getTarget(target);
    addListener(targetElement, id, update);
    return () => removeListener(targetElement, id);
  }, [offsetBottom, offsetTop, target, update]);
 
  return (
    <div ref={placeholderRef}>
      {affixStyle && <div style={placeholderStyle} />}
      <div
        ref={affixRef}
        className={className}
        style={{ ...(affixStyle || {}), ...(style || {}) }}
      >
        {children}
      </div>
    </div>
  );
});