Lottie是 Airbnb 发布的一款开源动画库,它适用于 Android、iOS、Web 和 Windows 的库。 它提供了一套从设计师使用 AE(Adobe After Effects)到各端开发者实现动画的工具流。
组件
项目中的lottie动画组件\mova_app_mall\src\pagesC\components\c-lottie\c-lottie.vue
多个动画、动画过大如何使用该组件?
- 动画传值
方式1:把JSON文件放在oss上(cdn),直接向组件传参数:src=”lottieSrc”
方式2:把JSON文件(小于1M)放在oss上,请求并缓存到storage中,要使用的时候,从storage获取,并向组件传参数:animationData=”animationData”
- 单个动画
通常采用src的方式传参
JavaScript
<cLottie
:class="{ offsetScreen: ifCanvasOffsetScreen }"
ref="cLottieRef"
:src="lottieSrc"
@Complete="onPrizeAnimationComplete"
width="1630rpx"
height="1630rpx"
:loop="false"
@EnterFrame="EnterFrame"
></cLottie>
mounted() {
this.lottieSrc = Vue.prototype.$preGiftAnimate1;
// 预加载动画
uni.request({ url: this.lottieSrc }).then(() => {
// 开始动画
this.animateInitTimer = setTimeout(() => {
const animationTimer = setTimeout(() => {
const cLottieRef = this.$refs.cLottieRef;
cLottieRef?.call('goToAndStop', [0, false]);
cLottieRef?.call('play');
this.showContainerTimer = setTimeout(
() => {
// 这里可以做业务逻辑,如显示一个弹窗或者其他逻辑,(2000)时间根据实际情况调整
},
2000
);
clearTimeout(animationTimer);
}, 300);
clearTimeout(this.animateInitTimer);
}, 1000);
});
<em>// 容错,2s后还没开始播放动画的话就直接显示</em>
const isAnimateStartTimer = setTimeout(() => {
if (!this.isAnimateStart) {
// 这里可以做业务逻辑,如显示一个弹窗或者其他逻辑
}
clearTimeout(isAnimateStartTimer);
}, 2000);
},
// 一个动画播放结束回调
onPrizeAnimationComplete() {
this.ifCanvasOffsetScreen = true;
console.log('播放完毕?');
},
// 开始动画回调
EnterFrame() {
this.isAnimateStart = true;
},- 分片动画(多个动画)
多个动画的时候,通常采用缓存多个不超过1M的JSON的方式,用animationData传参
JavaScript
<c-lottie
:class="{ offsetScreen: ifCanvasOffsetScreen }"
ref="cLottieRef"
:src="lottieSrc"
@Complete="onPrizeAnimationComplete"
width="1630rpx"
height="1630rpx"
:loop="false"
:animationData="animationData && animationData.length && animationData[currentLottieIndex].data"
@dataFailed="onDataFailed"
@EnterFrame="EnterFrame"
></c-lottie>
data() {
return {
currentLottieIndex: 0,
}
}
mounted() {
// 可以用lottieSrc兜底,防止取不到storage
if (
uni.getStorageSync('preGiftAnimate11') &&
uni.getStorageSync('preGiftAnimate12') &&
uni.getStorageSync('preGiftAnimate13')
) {
this.animationData = [
{ data: uni.getStorageSync('preGiftAnimate11'), showContainer: false },
{ data: uni.getStorageSync('preGiftAnimate12'), showContainer: false },
{ data: uni.getStorageSync('preGiftAnimate13'), showContainer: true },
];
} else {
this.lottieSrc = Vue.prototype.$preGiftAnimate1;
}
if (this.lottieSrc) {
// 预加载动画
uni.request({ url: this.lottieSrc }).then(() => {
// 开始动画
this.animateInitTimer = setTimeout(() => {
const animationTimer = setTimeout(() => {
const cLottieRef = this.$refs.cLottieRef;
cLottieRef?.call('goToAndStop', [0, false]);
cLottieRef?.call('play');
this.showContainerTimer = setTimeout(
() => {
// 这里可以做业务逻辑,如显示一个弹窗或者其他逻辑,(2000)时间根据实际情况调整
},
2000
);
clearTimeout(animationTimer);
}, 300);
clearTimeout(this.animateInitTimer);
}, 1000);
});
} else {
// 开始动画
this.animateInitTimer = setTimeout(() => {
const animationTimer = setTimeout(() => {
const cLottieRef = this.$refs.cLottieRef;
cLottieRef?.call('goToAndStop', [0, false]);
cLottieRef?.call('play');
clearTimeout(animationTimer);
}, 300);
clearTimeout(this.animateInitTimer);
}, 800);
}
// 容错,2s后还没开始播放动画的话就直接显示
const isAnimateStartTimer = setTimeout(() => {
if (!this.isAnimateStart) {
// 这里可以做业务逻辑,如显示一个弹窗或者其他逻辑
}
clearTimeout(isAnimateStartTimer);
}, 2000);
}
// 一个动画播放结束回调
onPrizeAnimationComplete() {
this.ifCanvasOffsetScreen = true;
console.log('播放完毕?');
if (!this.lottieSrc) {
if (this.currentLottieIndex < this.animationData.length - 1) {
// 加载下一个分片动画
this.currentLottieIndex++;
const animationTimer = setTimeout(() => {
const cLottieRef = this.$refs.cLottieRef;
cLottieRef?.call('goToAndStop', [0, false]);
cLottieRef?.call('play');
if (this.animationData[this.currentLottieIndex].showContainer) {
this.showContainerTimer = setTimeout(() => {
// 这里可以做业务逻辑,如显示一个弹窗或者其他逻辑,(200)时间根据实际情况调整
clearTimeout(this.showContainerTimer);
}, 200);
}
clearTimeout(animationTimer);
}, 300);
}
}
},
// 开始动画回调
<strong>EnterFrame</strong>() {
this.isAnimateStart = true;
},- 预加载动画/动画缓存/兜底容错
全局预加载/storage缓存:
JavaScript
// 全局预加载,在项目入口文件main.ts中预加载/storage缓存
const <strong>preloadRemoteConfig</strong> = async () => {
const json11 = `https://shop-oss.iot.mova-tech.com/mova_app_mall/activity/PreGift/preGift-pop-animate-1.json?t=${Date.now()}/data.json`;
const json12 = `https://shop-oss.iot.mova-tech.com/mova_app_mall/activity/PreGift/preGift-pop-animate-2.json?t=${Date.now()}/data.json`;
const json13 = `https://shop-oss.iot.mova-tech.com/mova_app_mall/activity/PreGift/preGift-pop-animate-3.json?t=${Date.now()}/data.json`;
const json1 = `https://shop-oss.iot.mova-tech.com/mova_app_mall/activity/PreGift/preGift-pop-animate.json?t=${Date.now()}/data.json`;
uni.request({
url: json11,
<strong>success</strong>: (<em>res</em>) => {
if (<em>res</em>.statusCode === 200 && <em>res</em>.data) {
try {
const jsonStr = JSON.stringify(<em>res</em>.data);
uni.setStorageSync('preGiftAnimate11', jsonStr);
console.log({ title: 'JSON 缓存成功' });
} catch (e) {
console.log({ title: '缓存失败', icon: 'none' });
console.error('缓存 JSON 出错:', e);
}
}
},
<strong>fail</strong>: (<em>err</em>) => {
console.log({ title: '请求 JSON 失败', icon: 'none' });
console.error('请求远程 JSON 出错:', <em>err</em>);
},
});
uni.request({
url: json12,
<strong>success</strong>: (<em>res</em>) => {
if (<em>res</em>.statusCode === 200 && <em>res</em>.data) {
try {
const jsonStr = JSON.stringify(<em>res</em>.data);
uni.setStorageSync('preGiftAnimate12', jsonStr);
console.log({ title: 'JSON 缓存成功' });
} catch (e) {
console.log({ title: '缓存失败', icon: 'none' });
console.error('缓存 JSON 出错:', e);
}
}
},
<strong>fail</strong>: (<em>err</em>) => {
console.log({ title: '请求 JSON 失败', icon: 'none' });
console.error('请求远程 JSON 出错:', <em>err</em>);
},
});
uni.request({
url: json13,
<strong>success</strong>: (<em>res</em>) => {
if (<em>res</em>.statusCode === 200 && <em>res</em>.data) {
try {
const jsonStr = JSON.stringify(<em>res</em>.data);
uni.setStorageSync('preGiftAnimate13', jsonStr);
console.log({ title: 'JSON 缓存成功' });
} catch (e) {
console.log({ title: '缓存失败', icon: 'none' });
console.error('缓存 JSON 出错:', e);
}
}
},
<strong>fail</strong>: (<em>err</em>) => {
console.log({ title: '请求 JSON 失败', icon: 'none' });
console.error('请求远程 JSON 出错:', err);
},
});
uni.request({ url: json1 });
Vue.prototype.$preGiftAnimate11 = json11;
Vue.prototype.$preGiftAnimate12 = json12;
Vue.prototype.$preGiftAnimate13 = json13;
Vue.prototype.$preGiftAnimate1 = json1;
};
preloadRemoteConfig();兜底容错:
JavaScript
// 1. 动画开始的时候标记动画一开始
// 开始动画回调
<strong>EnterFrame</strong>() {
this.isAnimateStart = true;
},
// 在初始化动画的时候加上容错
// 容错,2s后还没开始播放动画的话就直接显示
const isAnimateStartTimer = setTimeout(() => {
if (!this.isAnimateStart) {
// 这里可以做业务逻辑,如显示一个弹窗或者其他逻辑
}
clearTimeout(isAnimateStartTimer);
}, 2000);注意事项
JSON体积,一般不超过2M,动画实在太大的时候,可以考虑让UI【压缩】或者【切成多个JSON(小于1M),再由前端拼接】
注意预加载/缓存动画/容错兜底,防止出现动画加载不出来的情况,同时引发后续业务逻辑的阻断(如业务弹窗等)
缓存动画的时候,注意小程序缓存的json的体积不能大于1M,否则真机上会报错
width=”1630rpx” height=”1630rpx”,按照实际动画来手动调整




发表回复