前言
- 业务接口返回用户信息,需要在页面展示用户的装扮道具,其中这些装扮道具有静态的资源和动态的资源。动态的资源都是用AE生成的带图片资源的Lottie动画。接口返回的用户装扮都是cdn链接,其中动态资源返回的是zip链接。
- 这里我使用的是lottie-web airbnb.io/lottie/#/ 这个库。通过阅读官方文档可以得知,lottie是通过json对象来启动动画的,由于接口是一返回一个zip链接,其中zip文件包含json配置,和图片资源。所以我这里只能读取zip里的json配置文件,配置animationData,来播放lottie动画。其实最好还是直接path引用json文件路径。
3.实现步骤:
- 获取 ZIP 文件: 使用浏览器的 Fetch API 或其他适当的网络请求库,从 CDN 获取 ZIP 文件。
- 解析 ZIP 文件: 使用 JSZip 或类似的库解析 ZIP 文件。
- 读取 Lottie JSON 文件: 一旦解析 ZIP 文件,读取其中的 Lottie JSON 文件。
- 更改 JSON 中的资源路径: 在 Lottie JSON 文件中,找到资源路径相关的字段,将其更新为正确的路径。通常,Lottie JSON 文件中的资源路径是相对路径,需要将其更新为指向 ZIP 文件中实际图片资源的路径。
- 将更新后的 JSON 传递给 Lottie: 将更新后的 JSON 配置传递给 Lottie 库,以便正确加载和显示动画。
封装lottie组件
<script setup lang="ts">
import { ref, watch, onMounted, onUnmounted } from 'vue'
import lottie, { AnimationItem } from 'lottie-web'
const props = defineProps({
speed: {
type: Number,
default: 1,
},
animationData: {
type: Object,
required: true,
},
})
const animation = ref<AnimationItem | null>(null)
const lottieContainer = ref<HTMLElement | null>(null)
// 监听props.animationData变化
watch(
() => props.animationData,
() => {
loadAnimation()
}
)
const loadAnimation = () => {
if (animation.value) {
animation.value.destroy()
}
animation.value = lottie.loadAnimation({
container: lottieContainer.value as Element,
renderer: 'svg',
loop: true,
autoplay: true,
animationData: props.animationData,
})
animation.value.setSpeed(props.speed)
}
onMounted(() => {
loadAnimation()
})
onUnmounted(() => {
if (animation.value) {
animation.value.stop() // 停止动画
animation.value.destroy() // 销毁动画实例
}
})
</script>
<template>
<div class="lottie-container" ref="lottieContainer"></div>
</template>
<style scoped>
/* 根据需要添加样式 */
</style>
通过cdn资源链接读取zip文件配置并修改json配置
// 引入jsZip解压zip文件
import JSZip from 'jszip'
// 读取 ZIP 文件
export async function fetchAndReadZip(url) {
if (!url) {
console.log('无效的url!')
return
}
const zipFileUrl = url
try {
const response = await fetch(zipFileUrl)
const zipBlob = await response.blob()
const zip = await JSZip.loadAsync(zipBlob)
// 存储所有图片的 Promise
const imagePromises = []
// 创建一个映射表来存储图片路径和对应的 Blob URL
const blobUrlMap = {}
// 遍历 ZIP 文件,处理图片
for (const [relativePath, zipEntry] of Object.entries(zip.files)) {
if (relativePath.startsWith('__MACOSX/')) {
continue
}
if (zipEntry.name.match(/\.(jpg|jpeg|png)$/i)) {
const blob = await zipEntry.async('blob')
const blobUrl = URL.createObjectURL(blob)
let start = zipEntry.name.lastIndexOf('/') + 1 // 找到最后一个 / 的位置,并从其后一位开始截取
let result = zipEntry.name.substring(start) // 截取从 '/' 后到结尾的部分
blobUrlMap[result] = blobUrl
imagePromises.push(blob)
}
}
// 遍历 ZIP 文件中的所有文件
for (const [, zipEntry] of Object.entries(zip.files)) {
const filePath = zipEntry.name
// 根据文件路径中的后缀名判断是否为 JSON 文件
if (filePath.endsWith('.json')) {
let content = await zipEntry.async('string')
content = JSON.parse(content)
updateJsonPaths(content.assets, blobUrlMap)
return content
}
}
} catch (error) {
console.error('Failed to fetch and read ZIP file:', error)
}
}
// 更新 JSON 中的资源路径
function updateJsonPaths(jsonContent, blobUrlMap) {
// 例如,将原始路径更新为 Blob URL
jsonContent.forEach((item) => {
if (item.p) {
item.u = null
item.p = blobUrlMap[item.p]
}
})
}
在组件中使用lottie组件
<script setup lang="ts">
import { fetchAndReadZip } from '@/utils/fetchZip'
// lottie 动画对象
const animationData: any = ref(null)
// 通过接口获取资源链接 https://xxxx.com/xxx.zip
const getActivityUserRankInfo = async () => {
let res = await activityUserRankInfo({ activity_id: activityId })
const { my_rank, rank_list } = res.data.data
rankList.value = rank_list
myRankInfo.value = my_rank
if (my_rank.user_info.decoration.moving_head_pendant) {
animationData.value = await fetchAndReadZip(my_rank.user_info.decoration.moving_head_pendant)
}
}
<script>
<template>
<LottieComponent
v-if="animationData"
:animationData="animationData"
:speed="0.5"
/>
</template>
成功读取zip json文件修改资源路径,播放lottie动画
lottie资源链接mqimg.meequ.cn/hobi_dtgj_1…