gpt4 book ai didi

javascript - 基于 JSON 数据的 React JS 动画

转载 作者:可可西里 更新时间:2023-11-01 01:52:21 25 4
gpt4 key购买 nike

我正在使用 React/Redux 并将动画数据存储在 JSON 中并尝试让它显示在 React 页面上。

我正在使用 setTimeout(用于暂停)和 setInterval(用于动画移动)。但是,我似乎无法理解如何正确实现动画,并且认为我正在以完全错误的方式处理事情。

JSON 数据:

"objects": [

{
"title": "puppy",
"image_set": [
{
"image": "images/puppy_sitting.png",
"startx": 520,
"starty": 28,
"pause": 1000

},
{
"image": "images/puppy_walking.png",
"startx": 520,
"starty": 28,
"endx": 1,
"endy": 1,
"time": 1000
},
{
"image": "images/puppy_crouching.png",
"startx": 1,
"starty": 1,
"endx": 500,
"endy": 400,
"time": 2000
}

]
},
{
"title": "scorpion",
"image_set": [
{
"image": "images/scorping_sleeping.png",
"startx": 100,
"starty": 400,
"pause": 5000

},
{
"image": "images/scorpion_walking.png",
"startx": 100,
"starty": 400,
"endx": 500,
"endy": 400,
"time": 7000
},
{
"image": "images/scorpion_walking.png",
"startx": 500,
"starty": 400,
"endx": 100,
"endy": 400,
"time": 2000
},
{
"image": "images/scorpion_walking.png",
"startx": 100,
"starty": 400,
"endx": 200,
"endy": 400,
"time": 7000
},
{
"image": "images/scorpion_walking.png",
"startx": 200,
"starty": 400,
"endx": 100,
"endy": 400,
"time": 1000
}
]
}
]

每个对象可以有多个与之相关的图像。动画将继续不停地重复。每个对象都应该与其他每个对象同时移动,这样我就可以创建一个各种动物和对象围绕它移动的场景。

动画代码:

我很确定我在这里找错了树,但我的代码看起来像这样:

  // image_set is the list of images for a specific object
// object_num is the array index corresponding to the JSON objects array
// selected is the array index corresponding to which image in the image_set will be displayed
runAnimation(image_set, object_num, selected){

// Uses prevState so that we keep state immutable
this.setState(prevState => {
let images = [...prevState.images];

if (!images[object_num]){
images.push({image: null, x: 0, y: 0})

}

images[object_num].image = image_set[selected].image;
images[object_num].x = this.getFactoredX(image_set[selected].startx);
images[object_num].y = this.getFactoredY(image_set[selected].starty);
return {images: images};
})

if (image_set[selected].endx && image_set[selected].endy && image_set[selected].time){
let x = this.getFactoredX(image_set[selected].startx)
let y = this.getFactoredY(image_set[selected].starty)
let startx = x
let starty = y
let endx = this.getFactoredX(image_set[selected].endx)
let endy = this.getFactoredY(image_set[selected].endy)
let time = image_set[selected].time

let x_increment = (endx - x) / (time / 50)
let y_increment = (endy - y) / (time / 50)



let int = setInterval(function(){

x += x_increment
y += y_increment


if (x > endx || y > endy){
clearInterval(int)
}

this.setState(prevState => {
let images = [...prevState.images]

if (images[object_num]){
images[object_num].x = x
images[object_num].y = y
}


return {images: images};


})


}.bind(this),
50
)

}

if (image_set[selected].pause && image_set[selected].pause > 0){
selected++

if (selected == image_set.length){
selected = 0
}

setTimeout(function() {
this.runAnimation(image_set, object_num, selected)

}.bind(this),
image_set[selected].pause
)

}
else {
selected++

if (selected == image_set.length){
selected = 0
}
setTimeout(function() {
this.runAnimation(image_set, object_num, selected)

}.bind(this),
50
)
}


}

Redux 和 this.props.data

Redux 将数据作为 props 引入。因此,我有一个从我的 componentDidMount 和 componentWillReceiveProps 函数调用的函数,它将原始图像集传递给 loadAnimationFunction。

我的渲染器()

在我的 render() 函数中,我有这样的东西:

if (this.state.images.length > 1){
animated = this.state.images.map((image, i) => {
let x_coord = image.x
let y_coord = image.y
return (
<div key={i} style={{transform: "scale(" + this.state.x_factor + ")", transformOrigin: "top left", position: "absolute", left: x_coord, top: y_coord}}>
<img src={`/api/get_image.php?image=${image.image}`} />
</div>
)

})
}

x_factor/y_factor

在我的整个代码中,还引用了 x 和 y 因子。这是因为动画出现的背景可能会缩小或放大。因此,我还缩放了每个动画的开始和结束 x/y 坐标的位置,并缩放了动画图像本身。

时间和暂停时间

Time 指示动画应该花费的时间(以毫秒为单位)。暂停时间表示在移动到下一个动画之前暂停多长时间(以毫秒为单位)。

问题

代码没有流畅地移动动画,它们似乎偶尔会跳来跳去。

此外,当我在页面上的任意位置单击鼠标时,它会导致动画跳转到另一个位置。为什么点击鼠标会影响动画?

我注意到的一件事是,如果我打开控制台进行调试,这确实会减慢动画速度。

我可以对我的代码做些什么以使动画按预期工作?

最佳答案

您正在尝试使用 setInterval 对坐标和 absolute 位置执行 setState 来为您的元素设置动画。所有这些都无法实现出色的性能。

首先,setInterval 不应该用于动画,你应该更喜欢 requestAnimationFrame因为它将允许 60fps 动画,因为动画将在浏览器的下一次重绘之前运行。

其次,执行 setState 会重新渲染您的整个组件,这可能会对渲染时间产生影响,因为我假设您的组件不会只渲染您的图像。您应该尽量避免重新渲染未更改的内容,因此请尝试为动画隔离图像。

最后,当您使用 lefttop 属性定位您的元素时,但您应该坚持这一点,定位,而不是动画浏览器会逐个像素地制作动画,并且无法创造出良好的性能。相反,您应该使用 CSS translate() ,因为它可以进行亚像素计算,并将改为在 GPU 上工作,让您可以实现 60fps 的动画。有一个 good article Paul Irish 对此的看法。


也就是说,您可能应该使用 react-motion这将使您获得流畅的动画:

import { Motion, spring } from 'react-motion'

<Motion defaultStyle={{ x: 0 }} style={{ x: spring(image.x), y: spring(image.y) }}>
{({ x, y }) => (
<div style={{
transform: `translate(${x}px, ${y}px)`
}}>
<img src={`/api/get_image.php?image=${image.image}`} />
</div>
)}
</Motion>

还有 React Transition Group,Transition可以像上面解释的那样使用 translate 动画移动你的元素。你还应该去看看 React 动画文档 here .

也值得一试,是React Pose ,它非常易于使用,并且使用干净的 API 也能很好地执行。 Here是 React 的入门页面。


这是一个快速演示,它使用您的概念和坐/走/运行循环。请注意,react-motion 是唯一一种无需对过渡持续时间进行硬编码即可处理帧之间过渡的方法,这将 go against a fluid UI ,状态只处理不同的步骤。

引用 react-motion Readme :

For 95% of use-cases of animating components, we don't have to resort to using hard-coded easing curves and duration. Set up a stiffness and damping for your UI element, and let the magic of physics take care of the rest. This way, you don't have to worry about petty situations such as interrupted animation behavior. It also greatly simplifies the API.

如果您对默认 Spring 不满意,可以更改damplingstiffness 参数。有一个 app这可以帮助您获得最令您满意的那一款。

demo

Source

关于javascript - 基于 JSON 数据的 React JS 动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53531445/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com