我想用React和Typescript从这个代码笔中重新创建下划线效果

The Codepen: https://codepen.io/krakruhahah/pen/jOzwXww

我认为下面代码中的问题是接口,我开始声明我的类型,但它仍然无法识别它们.它说他们是任何人.但max被声明为number,但显示为any still.我不确定为什么.功能描述为注释.

tsx:

import React from 'react';
import Typography from '@mui/material/Typography';
import { Box } from '@mui/material';

interface Props {
   max: number;
}

const styles = {
   body: {
       width: "80%",
       margin: "10vw auto",
     },

     heading: {
       fontFamily: "Playfair Display, serif",
       fontSize: "10vw",
     },
     
     "subheading": {
       fontFamily: "Open Sans, sans-serif",
       fontSize: "1em",
       lineHeight: "1.5",
     },
     
     "@media screen and (min-width: 40em)": {
       body: {
         width: "50%",
       },
       heading:{
         fontSize: "6vw",
       },
     
       subheading: {
         fontSize: "1.75vw",
       }
     },
     
     "underline--magical": {
       backgroundImage: "linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%)",
       backgroundRepeat: "no-repeat",
       backgroundSize: "100% 0.2em",
       backgroundPosition: "0 88%",
       transition: "backgroundSize 0.25s ease-in",
       "&:hover": {
         backgroundSize: "100% 88%",
       },
     },
};

function Effect(props: Props) {

   // VARIABLES
const magicalUnderlines = Array.from(document.querySelectorAll('.underline--magical'));

const gradientAPI = 'https://gist.githubusercontent.com/wking-io/3e116c0e5675c8bcad8b5a6dc6ca5344/raw/4e783ce3ad0bcd98811c6531e40256b8feeb8fc8/gradient.json';

// HELPER FUNCTIONS

// 1. Get random number in range. Used to get random index from array.
const randNumInRange = max => Math.floor(Math.random() * (max - 1));

// 2. Merge two separate array values at the same index to 
// be the same value in new array.
const mergeArrays = (arrOne, arrTwo) => arrOne
 .map((item, i) => `${item} ${arrTwo[i]}`)
 .join(', ');

// 3. Curried function to add a background to array of elms
const addBackground = (elms) => (color) => {
 elms.forEach(el => {
   el.style.backgroundImage = color;
 });
}
// 4. Function to get data from API
const getData = async(url): Promise<XMLHttpRequest> => {
 const response = await fetch(url);
 const data = await response.json();
 return data.data;
}

// 5. Partial Application of addBackground to always apply 
// background to the magicalUnderlines constant
const addBackgroundToUnderlines = addBackground(magicalUnderlines);

// GRADIENT FUNCTIONS

// 1. Build CSS formatted linear-gradient from API data
const buildGradient = (obj) => `linear-gradient(${obj.direction}, ${mergeArrays(obj.colors, obj.positions)})`;

// 2. Get single gradient from data pulled in array and
// apply single gradient to a callback function
const applyGradient = async(url, callback): Promise<XMLHttpRequest> => {
 const data = await getData(url);
 const gradient = buildGradient(data[randNumInRange(data.length)]);
 callback(gradient);
}

// RESULT
applyGradient(gradientAPI, addBackgroundToUnderlines);
   return (
       <Box>
           <Typography sx={styles.heading}>
               Look At This <span style={styles['underline--magical']}>Pretty</span> Underline
           </Typography>
           <Typography sx={styles.subheading}>
               Wow this one is super incredibly cool, and this{' '}
               <span style={styles['underline--magical']}>one is on Multiple Lines!</span> I wish I had found this like thirty
               projects ago when I was representing the lollipop guild.
           </Typography>
       </Box>
   );
}
export { Effect };

推荐答案

  1. 为了生成随机梯度,你有两个数组colorsposition,但对于linear-gradient,我们需要一个元组字符串.我创建了一个辅助函数generateGradientRangeArray来获取这个字符串.

  2. 由于我们使用React,我们可以创建一个钩子(useGradient)来从外部获取数据并在这里进行转换.

  3. 使用@emotion和Material UI组件,我们向BoxTypography添加了其他属性

  4. 最后,我们创建Underline组件,判断渐变属性,并将props 传递给样式.

App.tsx

import styled from "@emotion/styled";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";

import { Underline } from "./Underline";
import useGradient from "./useGradient";

const Heading = styled(Typography)`
  font-family: "Playfair Display", serif;
  font-size: 10vw;
  @media screen and (min-width: 40em) {
    font-size: 6vw;
  }
`;
const Subheading = styled(Typography)`
  font-family: "Open Sans", sans-serif;
  font-size: 1em;
  @media screen and (min-width: 40em) {
    font-size: 1.75vw;
  }
`;

export default function App() {
  const gradient = useGradient();
  return (
    <div className="App">
      <Box>
        <Heading>
          Look At This <Underline gradient={gradient}>Pretty</Underline>{" "}
          Underline
        </Heading>
        <Subheading>
          Wow this one is super incredibly cool, and this{" "}
          <Underline gradient={gradient}>one is on Multiple Lines!</Underline> I
          wish I had found this like thirty projects ago when I was representing
          the lollipop guild.
        </Subheading>
      </Box>
    </div>
  );
}

useGradient.ts

import { useEffect, useState } from "react";
import { generateGradientRangeArray, randNumInRange } from "./Helpers";
import { GradientType, IResult } from "./types";

const GRADIENT_API =
  "https://gist.githubusercontent.com/wking-io/3e116c0e5675c8bcad8b5a6dc6ca5344/raw/4e783ce3ad0bcd98811c6531e40256b8feeb8fc8/gradient.json";

const useGradient = () => {
  const [gradients, setGradients] = useState<GradientType>();

  useEffect(() => {
    const getData = async (url: string): Promise<void> => {
      // get the data from the api
      const response = await fetch(url);
      const result = (await response.json()) as IResult;
      // Get single gradient from data pulled in array
      const gradient = result.data[randNumInRange(result.data.length)];
      const transform = generateGradientRangeArray(gradient);
      // set state with the result
      setGradients(transform);
    };
    // Catching errors
    getData(GRADIENT_API).catch(console.error);
  }, []);

  return gradients;
};

export default useGradient;

Underline.tsx

import styled from "@emotion/styled";
import { Props, GradientType } from "./types";

const UnderlineStyle = styled.span<{ gradient: GradientType }>`
  background-image: linear-gradient(
    ${(props) => props.gradient.direction},
    ${(props) => props.gradient.range}
  );
  background-repeat: no-repeat;
  background-size: 100% 0.2em;
  background-position: 0 88%;
  transition: background-size 0.25s ease-in;
  &:hover {
    background-size: 100% 88%;
  }
`;

export const Underline = ({ children, gradient }: Props) => {
  if (!gradient) return null;
  return <UnderlineStyle gradient={gradient}>{children}</UnderlineStyle>;
};

Helpers.ts

import { IGradient, GradientType } from "./types";
/// HELPER FUNCTIONS

// Get random number in range. Used to get random index from array.
export const randNumInRange = (max: number) =>
  Math.floor(Math.random() * (max - 1));

// Create range of colors for gradient
export const generateGradientRangeArray = (data: IGradient): GradientType => {
  const { colors, direction, name, positions } = data;
  const rangeColorsArray: string[] = [];

  for (const clr in colors) {
    for (const pos in positions) {
      if (clr === pos) {
        rangeColorsArray.push(`${colors[clr]} ${positions[pos]},`);
      }
    }
  }
  const createGradientString = rangeColorsArray.join(" ").slice(0, -1);

  return { name, direction, range: createGradientString };
};

types.ts

import { ReactNode } from "react";

export interface IGradient {
  name: string;
  direction: string;
  colors: string[];
  positions: string[];
}

export type GradientType = { range: string } & Pick<
  IGradient,
  "name" | "direction"
>;

export interface IResult {
  data: IGradient[];
}

export interface Props {
  children: ReactNode;
  gradient?: GradientType;
}

Edit dazziling-code

Javascript相关问答推荐

如何解决CORS政策的问题

setcallback是什么时候放到macrotask队列上的?

如何在bslib nav_insert之后更改导航标签的CSS类和样式?

JSDoc创建并从另一个文件导入类型

加载背景图像时同步旋转不显示的问题

编剧如何获得一个div内的所有链接,然后判断每个链接是否都会得到200?

变量的值在Reaction组件中的Try-Catch语句之外丢失

try 使用javascript隐藏下拉 Select

React.Development.js和未捕获的ReferenceError:未定义useState

Web Crypto API解密失败,RSA-OAEP

Webpack在导入前混淆文件名

将Node.js包发布到GitHub包-错误ENEEDAUTH

在画布中调整边上反弹框的大小失败

当代码另有说明时,随机放置的圆圈有时会从画布上消失

如果我的列有条件,我如何呈现图标?

输入数据覆盖JSON文件

无法在Adyen自定义卡安全字段创建中使用自定义占位符

如何缩小函数中联合返回类型的范围

如何从图表中映射一组图表-js使用REACT

鼠标进入,每秒将图像大小减小5%