- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在线查看 。
效果实现参考源码: Logo 聚集与散开 。
原效果代码基于 react jsx 类组件实现。依赖旧,代码冗余.
我将基于此进行重构,重构目标:
重构应该在还原的基础上,用更好的方式实现相同的效果。如果能让功能更完善,那就更好了.
在重构的过程中,注意理解:
说明:后面都是代码,对代码感兴趣的可以与源码比较一下;对效果感兴趣的,希望对你有帮助! 。
脚手架: vite-react+ts 。
main.tsx
为:
import ReactDOM from "react-dom/client";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<App />
);
注意:这儿删除了 严格模式 。
删除 index.css 。
修改 App.tsx 为:
import "./App.css";
function App() {
return (
<div className="App">
</div>
);
}
export default App;
App.css
为:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
yarn add rc-tween-one lodash-es -S
yarn add @types/lodash-es -D
rc-tween-one : Ant Motion 的一个动效组件 。
APP.tsx 。
import TweenOne from "rc-tween-one";
import LogoAnimate from "./logoAnimate";
import "./App.css";
function App() {
return (
<div className="App">
<div className="banner">
<div className="content">
<TweenOne
animation={{ opacity: 0, y: -30, type: "from", delay: 500 }}
className="title"
>
logo 聚合分散
</TweenOne>
</div>
<LogoAnimate />
</div>
</div>
);
}
export default App;
App.css 。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.banner {
width: 100%;
height: 100vh;
overflow: hidden;
background: linear-gradient(135deg, #35aef8 0%, #7681ff 76%, #7681ff 76%);
position: relative;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.banner .content {
height: 35%;
color: #fff;
}
.banner .content .title {
font-size: 40px;
background: linear-gradient(yellow, white);
-webkit-background-clip: text;
color: transparent;
}
.banner .logo-box {
width: 300px;
height: 330px;
}
.banner .logo-box * {
pointer-events: none;
}
.banner .logo-box img {
margin-left: 70px;
transform: scale(1.5);
margin-top: 60px;
opacity: 0.4;
}
.banner .logo-box .point-wrap {
position: absolute;
}
.banner .logo-box .point-wrap .point {
border-radius: 100%;
}
@media screen and (max-width: 767px) {
.banner {
flex-direction: column;
}
.banner .content {
order: 1;
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.banner {
width: 100%;
height: 100vh;
overflow: hidden;
background: linear-gradient(135deg, #35aef8 0%, #7681ff 76%, #7681ff 76%);
position: relative;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.banner .content {
height: 35%;
color: #fff;
}
.banner .content .title {
font-size: 30px;
}
.banner .logo-box {
width: 300px;
height: 330px;
}
.banner .logo-box * {
pointer-events: none;
}
.banner .logo-box img {
margin-left: 70px;
transform: scale(1.5);
margin-top: 60px;
opacity: 0.4;
}
.banner .logo-box .point-wrap {
position: absolute;
}
.banner .logo-box .point-wrap .point {
border-radius: 100%;
}
@media screen and (max-width: 767px) {
.banner {
flex-direction: column;
}
.banner .content {
order: 1;
}
}
重点重构文件 logoAnimate.tsx 。
import React, { useRef, useState, useEffect } from "react";
import TweenOne, { Ticker } from "rc-tween-one";
import type { IAnimObject } from "rc-tween-one";
import { cloneDeep, delay } from "lodash-es";
type Point = {
wrapStyle: {
left: number;
top: number;
};
style: {
width: number;
height: number;
opacity: number;
backgroundColor: string;
};
animation: IAnimObject;
};
const logoAnimate = () => {
const data = {
image:
"https://imagev2.xmcdn.com/storages/f390-audiofreehighqps/4C/D1/GKwRIDoHwne3AABEqQH4FjLV.png",
w: 200, // 图片实际的宽度
h: 200, // 图片实际的高度
scale: 1.5, // 显示时需要的缩放比例
pointSizeMin: 10, // 显示时圆点最小的大小
};
const intervalRef = useRef<string | null>(null);
const intervalTime = 5000;
const initAnimateTime = 800;
const logoBoxRef = useRef<HTMLDivElement>(null);
// 聚合:true,保证永远拿到的是最新的数据,useState是异步的,在interval中拿不到
const gatherRef = useRef(true);
// 数据变更,促使dom变更
const [points, setPoints] = useState<Point[]>([]);
// 同步 points 数据,保证永远拿到的是最新的数据,useState是异步的,在interval中拿不到
const pointsRef = useRef(points);
useEffect(() => {
pointsRef.current = points;
}, [points]);
const setDataToDom = (imgData: Uint8ClampedArray, w: number, h: number) => {
const pointArr: { x: number; y: number; r: number }[] = [];
const num = Math.round(w / 10);
for (let i = 0; i < w; i += num) {
for (let j = 0; j < h; j += num) {
const index = (i + j * w) * 4 + 3;
if (imgData[index] > 150) {
pointArr.push({
x: i,
y: j,
r: Math.random() * data.pointSizeMin + 12
});
}
}
}
const newPoints = pointArr.map((item, i) => {
const opacity = Math.random() * 0.4 + 0.1;
const point: Point = {
wrapStyle: { left: item.x * data.scale, top: item.y * data.scale },
style: {
width: item.r * data.scale,
height: item.r * data.scale,
opacity: opacity,
backgroundColor: `rgb(${Math.round(Math.random() * 95 + 160)}, 255, 255)`,
},
animation: {
y: (Math.random() * 2 - 1) * 10 || 5,
x: (Math.random() * 2 - 1) * 5 || 2.5,
delay: Math.random() * 1000,
repeat: -1,
duration: 3000,
ease: "easeInOutQuad",
},
};
return point;
});
delay(() => {
setPoints(newPoints);
}, initAnimateTime + 150);
intervalRef.current = Ticker.interval(updateTweenData, intervalTime);
};
const createPointData = () => {
const { w, h } = data;
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) return;
ctx.clearRect(0, 0, w, h);
canvas.width = w;
canvas.height = h;
const img = new Image();
img.crossOrigin = "anonymous";
img.src = data.image;
img.onload = () => {
ctx.drawImage(img, 0, 0);
const data = ctx.getImageData(0, 0, w, h).data;
setDataToDom(data, w, h);
};
};
useEffect(() => {
createPointData();
return () => {
removeInterval();
};
}, []);
// 分散数据
const disperseData = () => {
if (!logoBoxRef.current || !logoBoxRef.current.parentElement) return;
const rect = logoBoxRef.current.parentElement.getBoundingClientRect();
const boxRect = logoBoxRef.current.getBoundingClientRect();
const boxTop = boxRect.top - rect.top;
const boxLeft = boxRect.left - rect.left;
const newPoints = cloneDeep(pointsRef.current).map((item) => ({
...item,
animation: {
x: Math.random() * rect.width - boxLeft - item.wrapStyle.left,
y: Math.random() * rect.height - boxTop - item.wrapStyle.top,
opacity: Math.random() * 0.2 + 0.1,
scale: Math.random() * 2.4 + 0.1,
duration: Math.random() * 500 + 500,
ease: "easeInOutQuint",
},
}));
setPoints(newPoints);
};
// 聚合数据
const gatherData = () => {
const newPoints = cloneDeep(pointsRef.current).map((item) => ({
...item,
animation: {
x: 0,
y: 0,
opacity: Math.random() * 0.2 + 0.1,
scale: 1,
delay: Math.random() * 500,
duration: 800,
ease: "easeInOutQuint",
},
}));
setPoints(newPoints);
};
const updateTweenData = () => {
gatherRef.current ? disperseData() : gatherData();
gatherRef.current = !gatherRef.current;
};
const removeInterval = () => {
if (intervalRef.current) {
Ticker.clear(intervalRef.current);
intervalRef.current = null;
}
};
const onMouseEnter = () => {
if (!gatherRef.current) {
updateTweenData();
}
removeInterval();
};
const onMouseLeave = () => {
if (gatherRef.current) {
updateTweenData();
}
intervalRef.current = Ticker.interval(updateTweenData, intervalTime);
};
return (
<>
{points.length === 0 ? (
<TweenOne
className="logo-box"
animation={{
opacity: 0.8,
scale: 1.5,
rotate: 35,
type: "from",
duration: initAnimateTime,
}}
>
<img key="img" src={data.image} alt="" />
</TweenOne>
) : (
<TweenOne
animation={{ opacity: 0, type: "from", duration: 800 }}
className="logo-box"
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
ref={logoBoxRef}
>
{points.map((item, i) => (
<TweenOne className="point-wrap" key={i} style={item.wrapStyle}>
<TweenOne
className="point"
style={item.style}
animation={item.animation}
/>
</TweenOne>
))}
</TweenOne>
)}
</>
);
};
export default logoAnimate;
最后此篇关于重构:banner中logo聚合分散动画的文章就讲到这里了,如果你想了解更多关于重构:banner中logo聚合分散动画的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
谁能看看这个 fiddle http://jsfiddle.net/pkcwtone/1/并告诉我为什么我无法将图像完全放入导航中? 这是 html:
到目前为止,我有 9 个 Logo ,并且我按列表顺序显示该 Logo 。现在我要做的是,我必须显示前 3 个 Logo 并等待几秒钟,然后隐藏该 3 个 Logo 并再次显示接下来的 3 个 Log
我正在尝试 ACSLogo(Mac 版本的 Logo)中的递归程序,并希望返回 2 个整数的列表(基本上是 X 坐标和 Y 坐标)。我不知道如何让它返回 2 个值。它没有问题。 此外,当您创建一个列表
我有一个用户以 PNG 格式上传的 Logo 。 我的目标是将用户上传的 Logo 转换为白色。 像这样 - 这样它在较暗的背景下看起来不错。 我可以导出它并使用 Photoshop 获得我想要的东西
经过多次研究后,我没有弄清楚如何将我的 Web 应用程序的 Logo 与导航项对齐。我创建了 Logo 图像,但无法以正确的方式对齐它!希望你们中的一些人能帮助我。 这是Haml代码 %heade
我在 Joomla 2.5 的模板上使用 Gantry 该模板在第一点设置为托管一个小图像作为 Logo ,但我希望它在宽度方面更改为更大的图像。 因此,现在它在 ipad 上不起作用,因为它开箱即用
我正在工作的站点的 Logo 出现在左侧,但我希望它居中。我该怎么办?在下方找到 CSS 代码。 header .logo{ display: inline-block; padding: 0; ve
我确信这使用 jquery 相当简单,但我无法弄明白。我有一个带有 Logo 的网站,该网站加载时会出现。当用户将鼠标悬停在某个导航链接上时,我想将该 Logo 与不同的 Logo 交换。 当鼠标悬停
我想知道使用 LOGO 是否有任何真正的缺点?我知道它是用来教 child 的,但理论上它可以用于更高级别的项目。除了它的许多不同版本之外,还有什么真正的缺点吗? 最佳答案 除了实际问题(跨平台支持、
我一直在尝试使用公司文档中发布的两种简单方法替换 JASPERSOFT CE 中的 Logo 和背景图像。我面临的问题是它从 MYSQL 数据库加载 _THEMES\5A5D753\IMAGES\LO
当用户将鼠标悬停在导航栏上时,我试图让我的 Logo 从透明背景变为填充背景。 目前,我的 JQuery 在悬停时工作,但当用户离开导航时, Logo 不会变回透明 Logo 。
我知道之前已经回答过类似的问题。但我无法弄清楚哪种方法是最好的。我发现有两种方法: 使用img 标签获取两张图片,一张是小尺寸的,一张是大尺寸的。在大屏幕上隐藏小尺寸 Logo ,在小尺寸屏幕上则相反
我在页眉中使用的 Logo 没有背景,但我在 Logo 悬停时添加了背景。我希望 Logo 背景放大,但我使用的代码使 Logo 放大而不是背景......如何更改代码以在不影响 Logo 的情况下放
我试图将 Logo 与其下方的相应文本水平对齐,以便它们看起来美观且有序。目前,它们只是垂直的。我搜索了这个网站和许多其他网站,并尝试了不同的解决方案,但似乎没有任何效果。这是我的代码。 .intro
我正在尝试调整 Logo 的大小,并在不调整导航栏大小的情况下将标题添加到 Logo 的一侧。 What the current navbar looks like HTML:
Toggle navigation
在我的网站上,我有一个 Logo 图像,然后是公司名称。目前它是堆叠的,所以它是 Logo 图像,下面是公司名称。 我想要的是他们肩并肩。因此,左侧是 Logo 图像,右侧是公司名称。 我做错了什么?
我读过 标签 is inappropriate for a logo .但是,如果您的 Logo 是纯文本,您应该使用什么?我觉得 和 也不合适。这是一个示例: Comp
Berkeley Logo User Manual 告诉我们,所有在连字符后的命令行参数都将收集在变量中: If a command line argument is just a hyphen, t
我试图将 Logo 与几个导航链接对齐,其中大多数网站的 Logo 在左侧,几个链接在右侧(这是我正在努力实现的目标)。 我有一个媒体查询,使标题 Logo 显示在导航链接上方。 但是好像不行。 我确
我是一名优秀的程序员,十分优秀!