reactjs React如何在本地指定动画@关键帧和类

jvlzgdj9  于 2023-05-17  发布在  React
关注(0)|答案(5)|浏览(150)
function Loader() {
    var style = {
        border: '16px solid #eee',
        borderTop: '16px solid #3ae',
        borderRadius: '50%',
        width: '1cm',
        height: '1cm',
        animation: 'spin 2s linear infinite',
    }
    return (
        <div style={style}>
        <style>{`
            @keyframes spin {
                 0% { transform: rotate(0deg); }
                 100% { transform: rotate(360deg); }
            }
        `}</style>
        </div>
    )
}

有没有一种方法可以在本地指定@keyframes到组件(在这个例子中是一个组件函数),而不使用内联字符串?
另外,如果在组件渲染函数中指定<style>,如果有多个相同类的对象(或使用相同的@keyframes),是否会导致性能下降?
我们的想法是将<style>中的内容本地保存在组件中,我不想将其移动到.css文件中,但同时我也不想在只有一个实际上就足够的情况下重复数百个类/关键帧定义。

3ks5zfa0

3ks5zfa01#

如果不编写辅助函数或使用一些可以注入关键帧的标准库,这是不可能的,因为用于此的浏览器选项仍然是实验性的,并且不被广泛支持,例如animate函数。
https://developer.mozilla.org/en-US/docs/Web/API/Element/animate
当使用CSS模块从另一个文件(如css或JS文件)导入它们时,Webpack通常会为您完成注入繁重的工作。
我建议你要么导入CSS文件,要么为此目的检查样式组件帮助函数。

import React from "react";
import ReactDOM from "react-dom";
import { keyframes } from "styled-components";

function Loader() {
  var spin = keyframes`
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
`;

  var styles = {
    border: "16px solid #eee",
    borderTop: "16px solid #3ae",
    borderRadius: "50%",
    width: "1cm",
    height: "1cm",
    animation: `${spin} 2s linear infinite`
  };

  return <div style={styles} />;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Loader />, rootElement);
smdnsysy

smdnsysy2#

您可以使用与之前相同的方法来完成它,只需声明一个Keyframes组件来整理客户端代码。一些用法:

<Keyframes name="oscillate" from={{ opacity: 0.9 }} to={{ opacity: 0.2 }} />

<Keyframes name="oscillate" _0={{ opacity: 0.9 }} _100={{ opacity: 0.2 }} />

您需要在百分比值前面添加下划线或其他字母,但其他方面都是相同的。组件循环通过它的所有props输出格式化的css。使用jsx,React有一个特殊的CSS对象类型,需要转换为字符串,否则它只是一个组件。

import * as React from "react";

interface IProps {
  name: string;
  [key: string]: React.CSSProperties | string;
}

export const Keyframes = (props: IProps) => {
  const toCss = (cssObject: React.CSSProperties | string) =>
    typeof cssObject === "string"
      ? cssObject
      : Object.keys(cssObject).reduce((accumulator, key) => {
          const cssKey = key.replace(/[A-Z]/g, v => `-${v.toLowerCase()}`);
          const cssValue = (cssObject as any)[key].toString().replace("'", "");
          return `${accumulator}${cssKey}:${cssValue};`;
        }, "");

  return (
    <style>
      {`@keyframes ${props.name} {
        ${Object.keys(props)
          .map(key => {
            return ["from", "to"].includes(key)
              ? `${key} { ${toCss(props[key])} }`
              : /^_[0-9]+$/.test(key)
              ? `${key.replace("_", "")}% { ${toCss(props[key])} }`
              : "";
          })
          .join(" ")}
      }`}
    </style>
  );
};
balp4ylt

balp4ylt3#

下面是我们如何在不增加任何依赖性的情况下实现它。

{/*Your Js File Code */}

import { StrictMode } from "react";
import ReactDOM from "react-dom";
import React from "react";
import "./test.css";

class Anim extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      animationName: ""
    };
  }

  addStylesheetRules(rules) {
    var styleEl = document.createElement("style");
    document.head.appendChild(styleEl);
    var styleSheet = styleEl.sheet;
    styleSheet.insertRule(rules, 0);
  }

  clickHdl() {
    let animationName = `animation${Math.round(Math.random() * 100)}`;
    let keyframes = `
    @-webkit-keyframes ${animationName} {
        10% {-webkit-transform:translate(${Math.random() * 300}px, ${
      Math.random() * 300
    }px)} 
        90% {-webkit-transform:translate(${Math.random() * 300}px, ${
      Math.random() * 300
    }px)}
        100% {-webkit-transform:translate(${Math.random() * 300}px, ${
      Math.random() * 300
    }px)}
    }`;

    this.addStylesheetRules(keyframes);

    this.setState({
      animationName: animationName
    });
  }

  render() {
    let style = {
      animationName: this.state.animationName,
      animationTimingFunction: "ease-in-out",
      animationDuration: "0.6s",
      animationDelay: "0.0s",
      animationIterationCount: 1,
      animationDirection: "normal",
      animationFillMode: "forwards"
    };

    return (
      <div>
        <button type="button" onClick={this.clickHdl.bind(this)}>
          Animation!
        </button>
        <div className="box" style={style}></div>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <StrictMode>
    <Anim />
  </StrictMode>,
  rootElement
);

{/*Css Code test.css */}

.box {
  width: 30px;
  height: 30px;
  background: red;
  border-radius: 50%;
  cursor: pointer;
}

演示:https://codesandbox.io/s/reverent-sun-qjo91?file=/src/index.js

dhxwm5r4

dhxwm5r44#

这个答案是基于罗恩·纽科姆的回答。对我来说,把所有的动画 prop 都粘到它们自己的显式 prop 中似乎更简单,而不必担心任何前缀。

type IProps = {
  name: string;
  animationProps: Record<string, React.CSSProperties | string>;
};

const toCss = (cssObject: React.CSSProperties | string) =>
  typeof cssObject === "string"
    ? cssObject
    : Object.keys(cssObject).reduce((accumulator, key) => {
      const cssKey = key.replace(/[A-Z]/g, (v) => `-${v.toLowerCase()}`);
      const cssValue = (cssObject as any)[key].toString().replace("'", "");
      return `${accumulator}${cssKey}:${cssValue};`;
    }, "");

const Keyframe = ({ name, animationProps }: IProps) => {
  const cssRules = Object.entries(animationProps).map(
    ([key, value]) => `${key} { ${toCss(value)} }`
  );
  return (
    <style>
      {`@keyframes ${name} {
        ${cssRules.join("\n")}
      }`}
    </style>
  );
};

export default Keyframe;

包括它就像

<Keyframe
  name="appear"
  animationProps={{ from: { opacity: 0 }, to: { opacity: 1 } }}
/>
vqlkdk9b

vqlkdk9b5#

我发现的最好的方法是在代码中放置一个样式标签,通过类选择div并添加在其属性中创建的动画。

import React from 'react'

export default function Test(){
 return(
   <style>
{`
                .PropText{
                    display: -webkit-inline-box;                    
                    font-Size: 50px;
                    font-family: fantasy;
                    text-align: center;
                    animation: mymove 5s infinite;
                }
                
                @keyframes mymove {
                    0%   {color: #DE354C;}
                    30%  {color: #932432;}
                    60%  {color: orange;}
                    85%  {color: lightyellow;}
                    100% {color: #F3F3F3;}
                }
            `}
   </style>
   <div>
         <p className="PropText">
                   Sample Text
         </p>
   </div>
 );
}

相关问题