使用 react-visibility-sensor 在第一次滚动后保持元素可见

IT技术 reactjs scroll react-hooks
2021-05-27 09:12:00

使用 react-visibility-sensor 我创建了一个更高的组件来为我的项目部分滚动动画。

我试图让它只在第一个滚动条上工作时遇到问题。目前这些部分出现和消失。

任何帮助将非常感激。干杯!

import VisibilitySensor from 'react-visibility-sensor';

export const SlideUp = ({ children }) => {
  const [isVisible, setVisibility] = useState(false);

  const onChange = visiblity => {
    setVisibility(visiblity);
  };

  return (
    <VisibilitySensor
      partialVisibility
      offset={{ top: 200 }}
      onChange={onChange}
    >
      <div
        style={{
          transition: `opacity ${0.5}s ease, transform ${0.5}s ease`,
          opacity: isVisible ? 1 : 0,
          transform: isVisible ? `translateY(${0}px)` : `translateY(${20}px)`,
        }}
      >
        {children}
      </div>
    </VisibilitySensor>
  );
};```

- use example:

<SlideUp>
  <Section />
</SlideUp>
4个回答

我的解决方案是将 React Pose 与 React Visibility 混合使用。

可见性触发 React Pose 中的动画,该动画只发生一次。动画依赖于姿势而不是可见性。

import VisibilitySensor from 'react-visibility-sensor';
import posed from 'react-pose';

const PoseDiv = posed.div({
  enter: {
    y: 0,
    opacity: 1,
    transition: {
      duration: 300,
      ease: 'easeIn',
    },
  },
  exit: { y: 20, opacity: 0 },
});

export const SlideUp = ({ children }) => {
  const [isVisible, setVisibility] = useState(false);
  const [entered, setEntered] = useState(false);

  const onChange = visiblity => {
    setVisibility(visiblity);
  };

  useEffect(() => {
    if (isVisible) {
      setEntered(true);
    }
  }, [isVisible]);

  return (
    <>
      <VisibilitySensor
        partialVisibility
        offset={{ top: 100 }}
        onChange={onChange}
      >
        <PoseDiv pose={entered ? 'enter' : 'exit'}>{children}</PoseDiv>
      </VisibilitySensor>
    </>
  );
}; 

我希望它可以帮助别人。干杯!

PS:由于 React Pose 现在已弃用,因此需要更新此解决方案。

https://www.framer.com/api/motion/migrate-from-pose/

import VisibilitySensor from 'react-visibility-sensor';

export const SlideUp = ({ children }) => {
  const [isVisible, setVisibility] = useState(false);

  const onChange = visiblity => {
    setVisibility(visiblity);
  };

  return (
    <VisibilitySensor
      partialVisibility
      offset={{ top: 200 }}
      onChange={onChange}
    >
      <div
        className={`example ${isVisible ? 'visible' : ''}`}
      >
        {children}
      </div>
    </VisibilitySensor>
  );
};

CSS

.example{
  ...
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.example.visible{
  opacity: 1;
  transform: translateY(0px);
}

尝试使用 className

我认为您正在切换可见性状态,以保持 ui 在显示后可见,不要将状态更改为不可见

只是改变

const onChange = visiblity => {
   setVisibility(visiblity);
  };

const onChange = visiblity => {
if(visiblity){
 setVisibility(visiblity);
}
};

这是我一直在使用的解决方案。只需使用hasBeenVisible渲染props而不是isVisible.

import React, { useState } from "react";
import VisibilitySensor from "react-visibility-sensor";

/**
 * VisibilitySensor does not implement some kind of funcionality to track first time
 * visibility. This component extends VisibilitySensor compoment to provide this
 * feature. Just use `hasBeenVisible` render prop instead of `isVisible`.
 * 
 * https://github.com/joshwnj/react-visibility-sensor/issues/117#issuecomment-686365798
 */
const AppearSensor = ({
  onChange,
  children,
  ...rest
}) => {
  const [hasBeenVisible, setHasBeenVisible] = useState(false);

  return (
    <VisibilitySensor {...rest} onChange={(isVisible) => {
      if (isVisible) setHasBeenVisible(true)
      if (onChange) onChange(isVisible)
    }}>
      {
        ({
          isVisible,
          ...restRenderProps
        }) => {
          return children({ isVisible, ...restRenderProps, hasBeenVisible })
        }
      }
    </VisibilitySensor>
  );
};

AppearSensor.propTypes = VisibilitySensor.propTypes
AppearSensor.defaultProps = VisibilitySensor.defaultProps

export default AppearSensor;