我是使用Javascript + CSS + React的新手,并且被严重卡住了。感谢任何帮助!!下面描述的是一个简化版本,以突出显示关键请求
我的react组件描述:
在屏幕上从A点垂直无限移动到B点的点。A点和B点是屏幕平面上随机分配的点。这两个点有相同的x坐标,但不同的y坐标,使垂直运动。所以从A到B的每一段路程都有三个随机参数:x, y1和y2。一旦到达B点,它在a点重新开始。
期望状态:
问1 -一旦点到达终点B,我希望能够重新随机x, y1和y2为我的组件。
问2 -我需要这个组件的几个实例(假设20),每个实例都有自己的随机事件独立进行。
我目前的方法:
步骤1:在组件的css文件中,我将--x
,--y1
和--y2
作为:root
类中的变量来编写动画代码:
:root { /* Values assigned are just fallback values */
--x: 100px;
--y1: 10px;
--y2: 400px;
}
.spark div { /* spark is the `className` for the div that contains the dot (shown in Step 2) */
height: 20px;
width: 20px;
border-radius: 50%;
position: absolute;
left: var(--x);
top: var(--y2);
background: rgba(0, 0, 0, 1);
animation: myOrbit 15s linear infinite;
}
@keyframes myOrbit {
0% {
transform: translateY(var(--y1));
}
100% {
transform: translateY(var(--y2));
}
}
步骤2:我在组件的jsx代码中使用document.documentElement.style.setProperty("--x", x + "vw");
,如下所示:
const Spark = () => {
document.documentElement.style.setProperty("--x", Math.random()*500 + "px");
document.documentElement.style.setProperty("--y1", Math.random()*500 + "px");
document.documentElement.style.setProperty("--y2", Math.random()*500 + "px");
return (
<div className="spark">
<div />
</div>
);
};
export default Spark;
第3步:我在App.js中使用下面的代码调用这个组件:
import Spark from "./components/Spark.js";
const App = () => {
return (
<div className="sparks">
<Spark />
<Spark />
<Spark />
<Spark />
<Spark />
</div>
);
};
export default App;
步骤4:使用index.js和index.html:
src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App.js";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
公共/index . html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>visor</title>
</head>
<body style="margin: 0%; padding: 0%">
<div id="root"></div>
</body>
</html>
问题:
- Spark组件的最后一个实例生成的随机x、y1和y2值将应用于所有先前的实例。所以我只得到5个重叠的点而不是5个不同的
- 我无法在随后的A-B循环之间改变x, y1, y2。我不确定从哪里开始
非常感谢您的帮助
让我们先说明一下,React(开箱即用)没有一种直接的方式来添加从React组件中获取变量的动画。
如果你打算做比这更复杂的事情,我强烈建议你去看看那些能帮你解决这个问题的库。这里讨论了一些选项
你面临的主要问题似乎是如何为每个点应用动画.这不会影响到其他点的逻辑。
为了做到这一点,我们将为每个Spark创建一个单独的动画,并在组件中创建一个随机的x, y1和y2。
你似乎面临的第二个问题是如何分配新的随机值,当动画完成,react提供钩子,我们可以使用onAnimationIteration
触发一些代码来处理。
在这个代码中,你可以发现整个部分是一起工作的。
import React from "react";
const Spark = () => {
const name = `spark_${Math.random()}`.replace(".", ""); // create a random name
const [x, setX] = React.useState(Math.random() * 500); // keep state for x
const [y1, setY1] = React.useState(Math.random() * 500); // y1
const [y2, setY2] = React.useState(Math.random() * 500); // and y2
// build the animation string
const animationStyle = `{ 0% {transform: translate(${x}px,${y1}px);} 100% {transform: translate(${x}px,${y2}px);} }`;
React.useEffect(() => { // useEffect runs whenever the provided dependancies change. in the effect well create the stylesheet and add it to the dom
// Creating a style element, to add the keyframes
const styleSheet = document.createElement("style");
styleSheet.type = "text/css";
styleSheet.id = x;
document.head.appendChild(styleSheet);
// Adding The Keyframes
styleSheet.sheet.insertRule(
`@keyframes ${name} ${animationStyle}`,
styleSheet.length
);
// return a cleanup function for when the element unmounts
return () => styleSheet.remove(); // this cleanup will remove the stylesheet when it's not needed anymore
}, [animationStyle, name, x]);
return (
<div className="spark">
<div
style={{ //you can pass css styles to the dom via react,
animation: `${name} 1s linear infinite`, // here we set the animation
transform: `translate(${x}px, ${y1}px)` // here we provide some initial values.
}}
onAnimationIteration={() => { // react can listen to dom event, here we trigger some code eacht time the animation starts a new itteration
setX(Math.random() * 500); // set new values
setY1(Math.random() * 500);
setY2(Math.random() * 500);
}}
/>
</div>
);
};
export default Spark;
你可以通过返回一个组件数组来呈现多个
import "./styles.css";
import Spark from "./spark";
export default function App() {
return (
<div className="sparks">
{Array(20)
.fill(0)
.map((_, i) => (
<Spark key={i} />
))}
</div>
);
}