我这里有一个文本动画,工作完美.我现在要添加的是一个交点观察者,这样动画只在我向下滚动到长方体时开始.

因此,我所做的是:

但是Typescript告诉我在containerRef?.current时有一个错误:

Argument of type 'IntersectionObserver' is not assignable to parameter of type 'Element'.
  Type 'IntersectionObserver' is missing the following properties from type 'Element': attributes, classList, className, clientHeight, and 160 more.

我不知道如何解决这个错误.我认为这也是我的ref={containerRef}投错的原因

The expected type comes from property 'ref' which is declared here on type 'IntrinsicAttributes & { component: ElementType<any>; } & SystemProps<Theme> & { children?: ReactNode; component?: ElementType<...> | undefined; ref?: Ref<...> | undefined; sx?: SxProps<...> | undefined; } & CommonProps & Omit<...>'

The animation:

TextAnimation.tsx

import { Box, Stack, Typography } from '@mui/material';
import React, { useRef, useEffect, useState } from 'react';
import styled, { keyframes } from 'styled-components';

const showTopText = keyframes`
  0% { transform: translate3d(0, 100% , 0); }
  40%, 60% { transform: translate3d(0, 50%, 0); }
  100% { transform: translate3d(0, 0, 0); }
`;
const showBottomText = keyframes`
  0% { transform: translate3d(0, -100%, 0); }
  100% { transform: translate3d(0, 0, 0); }
`;

const Section = styled.section`
  width: calc(100% + 10vmin);
  display: flex;
  flex-flow: column;
  padding: 2vmin 0;
  overflow: hidden;
  &:last-child {
    border-top: 1vmin solid white;
  }
`;

const Block = styled.div<{ numOfLine: number }>`
  position: relative;
`;
const TopAnimateBlock = styled(Block)`
  animation: ${showTopText} calc(0.5s * ${props => props.numOfLine}) forwards;
  animation-delay: 0.5s;
  transform: translateY(calc(100% * ${props => props.numOfLine}));
`;
const BottomAnimateBlock = styled(Block)<{ delayTopLine: number }>`
  animation: ${showBottomText} calc(0.5s * ${props => props.numOfLine}) forwards;
  animation-delay: calc(0.7s * ${props => props.delayTopLine});
  transform: translateY(calc(-100% * ${props => props.numOfLine}));
`;

const TextStyle = styled.p<{ color: string }>`
  font-family: Roboto, Arial, sans-serif;
  font-size: 12vmin;
  color: ${props => props.color};
`;


const useElementOnScreen = (options) => {
    const containerRef = useRef<IntersectionObserver | null>(null);
    const [isVisible, setIsVisible] = useState(false);

    const callbackFunction = (entries) => {
        const [entry] = entries;
        setIsVisible(entry.isIntersecting);
    };

    useEffect(() => {
        const observer = new IntersectionObserver(callbackFunction, options);

        if (containerRef.current) observer.observe(containerRef?.current);

        return () => {
            if (containerRef.current) observer.unobserve(containerRef?.current);
        };
    }, [containerRef, options]);

    return [containerRef, isVisible];
};

export function Details() {
    const [containerRef, isVisible] = useElementOnScreen({
        root: null,
        rootMargin: '0px',
        threshold: 1.0,
    });

    return (
    <>
    <Typography>Scroll Down</Typography>
     <Box ref={containerRef}>
      <Section>
        <TopAnimateBlock numOfLine={2}>
          <TextStyle color="grey">mimicking</TextStyle>
          <TextStyle color="white">apple's design</TextStyle>
        </TopAnimateBlock>
      </Section>
      <Section>
        <BottomAnimateBlock numOfLine={1} delayTopLine={2}>
          <TextStyle color="white">for the win!</TextStyle>
        </BottomAnimateBlock>
      </Section>
    </Box>
</>
  );
};

推荐答案

我大致可以在代码中找到两个问题:

首先是这句话:

 const containerRef = useRef<IntersectionObserver | null>(null);

通用useRef的实现是用IntersectionObserver | null完成的.这意味着ref容器将包含IntersectionObservernull的实例.但相反,ref被分配到Box(对于那些不熟悉material UI的人,这将是div).因此应该将其更改为类似以下内容:

  const containerRef = useRef<HTMLDivElement | null>(null);

其次,没有声明钩子的返回类型,因为它是一个数组[containerRef, isVisible],TS自动检测它.Typescript推断的类型为:

Typescript return type for the hook

(boolean | React.MutableRefObject<HTMLDivElement | null>)[].

由于该类型实际上是一个元组,并且返回的两个数组元素的类型不同,因此推断的类型不正确,TS会发出投诉.

在定义钩子时声明这一点可以防止Typescript抱怨.

const useOnScreen = <T,>(options : T): [MutableRefObject<HTMLDivElement | null>, boolean] => {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const [isVisible, setIsVisible] = useState(false);

  const callbackFunction = (entries : : IntersectionObserverEntry[]) => {
    const [entry] = entries;
    setIsVisible(entry.isIntersecting);
  };

  useEffect(() => {
    const observer = new IntersectionObserver(callbackFunction, options);

    if (containerRef.current) observer.observe(containerRef?.current);

    return () => {
      if (containerRef.current) observer.unobserve(containerRef?.current);
    };
  }, [containerRef, options]);

  return [containerRef, isVisible];
};

link解释元组返回类型和数组返回类型之间的差异.

Javascript相关问答推荐

追踪执行顺序

React redux状态未在React-Router库中呈现

JavaScript Date对象在UTC中设置为午夜时显示不正确的日期

React对话框模式在用户单击预期按钮之前出现

如何用显示网格平滑地将元素从一个地方移动到另一个地方?

调用removeEvents不起作用

. NET中Unix时间转换为日期时间的奇怪行为

判断表格单元格中是否存在文本框

成功完成Reducers后不更新状态

数字时钟在JavaScript中不动态更新

v—自动完成不显示 Select 列表中的所有项目

如何将数据块添加到d3力有向图中?

使用Nuxt Apollo在Piniastore 中获取产品细节

NG/Express API路由处理程序停止工作

Google脚本数组映射函数横向输出

WebSocketException:远程方在未完成关闭握手的情况下关闭了WebSocket连接.&#三十九岁;

Phaser3 preFX addGlow不支持zoom

当我点击一个按钮后按回车键时,如何阻止它再次被点击

ngOnChanges仅在第二次调用时才触发

FindByIdAndUpdate在嵌套对象中创建_id