优秀的编程知识分享平台

网站首页 > 技术文章 正文

Unity全流程开发热门游戏BallSort,助力迈入游戏领域-明月来相照

nanyue 2024-10-24 11:49:22 技术文章 3 ℃

手写一个 React 动画组件

Unity全流程开发热门游戏BallSort,助力迈入游戏领域

download:https://97yrbl.com/t-645.html

但是假如当前动画除了展现还需求其他交互,以至是一个组件需求动画效果,运用图片格式就不合理了。于是我写一个极端简单的 css 动画库 rc-css-animate。这里直接运用 animate.css 作为 css 动画的依赖库。 animate.css 不但提供了很多交互动画款式类,也提供了动画运转速度,延迟,以及反复次数等款式类。

能够看到,默许的 animate.css 构建动画都需求携带前缀 “animate__”。

An animated element
当然,该库是对 css 动画停止了一层封装,仍然支持其他动画库以及本人手写的 css 动画,但假如开发者需求对动画停止各种复杂控制,不引荐运用此库。

运用
能够应用如下方式运用:

import React, { useRef } from "react";
import ReactCssAnimate from "rc-css-animate";

// 引入 animate.css 作为动画依赖
import "animate.css";

function App() {
const animateRef = useRef(null);

return (

<ReactCssAnimate
// 定义当前展现动画的组件
// 默许运用 div
tag="div"
// 当前组件的 className
className=""
// 当前组件的 style
style={{}}
// 当前组件的 ref
ref={animateRef}
// 动画前缀
clsPrefix="animate__"
// 当前动画的 className
animateCls="animated backInDown infinite"
// 动画开端时分能否处于展现状态
initialVisible={false}
// 获取动画完毕能否处置展现状态
getVisibleWhenAnimateEnd={(cls) => {
// 假如当前 animateCls 中有 Out
// 返回 false 则会在动画完毕后不再显现
if (cls.includes("Out")) {
return false;
}
return true;
}}
// 动画完毕回调
onAnimationEnd={() => {
console.log("done");
}}
>

测试动画



);
}
ReactCssAnimate 运用了 React hooks,但是也提供了兼容的类组件。同时也提供了全局的前缀设置。

import React from "react";
import {
// 运用类组件兼容之前的版本
CompatibleRAnimate as ReactCssAnimate,
setPrefixCls,
} from "rc-css-animate";

// 引入 animate.css 作为动画依赖
import "animate.css";

// 设置全局 prefix,会被当前组件掩盖
setPrefixCls("animate__");

/** 构建动画块组件 */
function BlockWrapper(props) {
// 需求获取并传入 className, children, style
const { className, children, style } = props;
return (
<div
className={className}
style={{
background: "red",
padding: 100,
...style,
}}
>
{children}

);
}

function App() {
return (

<ReactCssAnimate
tag={BlockWrapper}
// 当前动画的 className
animateCls="animated backInDown infinite"
>

测试动画


);
}
源码解析
源代码较为简单,是基于 createElment 和 forwardRef 构建完成。其中 forwardRef 会将当前设置的 ref 转发到内部组件中去。关于 forwardRef 不熟习的同窗能够查看一下官网中关于 Refs 转发的文档。

import React, {
createElement,
forwardRef,
useCallback,
useEffect,
useState,
} from "react";
import { getPrefixCls } from "./prefix-cls";
import { AnimateProps } from "./types";

// 全局的动画前缀
let prefixCls: string = "";

const getPrefixCls = (): string => prefixCls;

// 设置全局的动画前缀
export const setPrefixCls = (cls: string) => {
if (typeof cls !== "string") {
return;
}
prefixCls = cls;
};

const Animate = (props: AnimateProps, ref: any) => {
const {
tag = "div",
clsPrefix = "",
animateCls,
style,
initialVisible,
onAnimationEnd,
getVisibleWhenAnimateEnd,
children,
} = props;

// 经过 initialVisible 获取组件的显隐,假如没有则默许为 true
const [visible, setVisible] = useState(initialVisible ?? true);

// 当前不需求展现,返回 null 即可
if (!visible) {
return null;
}

// 没有动画类,直接返回子组件
if (!animateCls || typeof animateCls !== "string") {
return <>{children}</>;
}

useEffect(() => {
// 当前没获取恳求完毕的设置显现躲藏,直接返回,不停止处置
if (!getVisibleWhenAnimateEnd) {
return;
}
const visibleWhenAnimateEnd = getVisibleWhenAnimateEnd(animateCls);

// 假如动画完毕后需求展现并且当前没有展现,直接停止展现
if (visibleWhenAnimateEnd && !visible) {
setVisible(true);
}
}, [animateCls, visible, getVisibleWhenAnimateEnd]);

const handleAnimationEnd = useCallback(() => {
if (!getVisibleWhenAnimateEnd) {
onAnimationEnd?.();
return;
}

// 当前处于展现状态,且动画完毕后需求躲藏,直接设置 visible 为 false
if (visible && !getVisibleWhenAnimateEnd(animateCls)) {
setVisible(false);
}
onAnimationEnd?.();
}, [getVisibleWhenAnimateEnd]);

let { className = "" } = props;

if (typeof className !== "string") {
className = "";
}

let animateClassName = animateCls;

// 获取最终的动画前缀
const finalClsPrefix = clsPrefix || getPrefixCls();

// 没有或者动画前缀不是字符串,不停止处置
if (!finalClsPrefix || typeof finalClsPrefix !== "string") {
animateClassName = animateCls.split(" ").map((item) =>
`${finalClsPrefix}${item}`
).join(" ");
}

// 创立并返回 React 元素
return createElement(
tag,
{
ref,
onAnimationEnd: handleAnimationEnd,
// 将传送的 className 和 animateClassName 兼并
className: className.concat(` ${animateClassName}`),
style,
},
children,
);
};

// 应用 forwardRef 转发 ref
// 第一个参数是 props,第二个参数是 ref
export default forwardRef(Animate);
以上代码全部在 rc-css-animate 中。这里也欢送各位小同伴提出 issue 和 pr。

Tags:

最近发表
标签列表