IOS动画卡顿问题
问题描述
使用css+js实现不断生成元素并向后滑动,越往后滑动元素越小的效果,但是在IOS上滑动看起来一顿一顿的。
大致代码如下(vue2):
// 父组件
<Obj
v-for="obj in objs"
:key="obj.id"
:obj="obj"
/>
// methods
createAnimation() {
const update = t => {
// ...
// 每1s增加一个元素
if (...) {
this.addObj();
}
// 每1帧,通过js修改元素位置和尺寸
this.objs.forEach((obj, index) => {
obj.offsetY += ...;
obj.scale += ...;
obj.offsetX += ...;
});
requestAnimationFrame(update);
};
requestAnimationFrame(update);
}
// Obj组件
<img class="obj" ref="obj":src="img" :style="getStyle" />
// computed
getStyle() {
// 通过computed计算元素大小和位置
return {
width: this.obj.width,
marginLeft: -this.obj.width / 2,
transform: `translate(${this.obj.offsetX}, ${
this.obj.offsetY
}) scale(${this.obj.scale})`
};
}
解决:
使用元素.animate()创建动画
// 父组件
createAnimation() {
const update = t => {
// ...
// 不在这里修改元素位置和尺寸
// this.objs.forEach((obj, index) => {
// obj.offsetY += ...;
// obj.scale += ...;
// obj.offsetX += ...;
// });
requestAnimationFrame(update);
};
requestAnimationFrame(update);
}
// Obj组件 mounted里调用
async createObjAnimation() {
let obj = this.$refs.obj;
const keyframe = [
// 初始位置和尺寸
{
transform: `translate(${this.obj.offsetX}, ${
this.obj.offsetY
}) scale(1)`
},
// 3s后,该元素动画结束时的位置和尺寸
{
transform: `translate(${this.obj.finalOffsetX}, ${
this.obj.finalOffsetY
}) scale(0.3)`
}
];
this.animation = obj.animate(keyframe, {
duration: 3000,
easing: "linear"
});
this.animation.play();
}
失败尝试
- 使用will-change: transform; 发现没有效果。
- 观察卡顿情况,发现好像是每次生成一个新的元素,页面上已存在的滑动元素就会顿一下,所以尝试一开始生成所有需要的元素,然后再js+css每隔1s依次移动1个元素,发现还是卡。
补充
版本较低的iOS可能不支持这种方式(我的iOS版本为12.1.4,可以显示卡顿的那种效果,但是换成animate()页面上无法显示元素)。