提示:如果是webpack环境的,参考:Pag格式在vue3中的简单使用方法_pag文件-CSDN博客
下面展示的是在vite环境下配置pag
1、安装libpag
npm i libpag --save
2、安装rollup-plugin-copy
npm i rollup-plugin-copy --save
官网使用libpag参考链接:Web端接入指南 · PAG官网 | PAG动效
3、封装pag组件
下面是一个完整的pag组件,我命名为pagImg
<template>
<div>
<canvas :id="'pag' + timeId" class="pag-size"></canvas>
</div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref, watch } from 'vue'
import { PAGInit } from 'libpag';
const props = defineProps({
url: {
type: String,
default: '',
}
})
const timeId = ref(Math.floor(new Date().getTime() * Math.random())); // 使该图表保持唯一id
const urlValue = ref(props.url) //https://www.mustake.net/loading.pag
const initPag = async () => {
const dom = document.getElementById(`pag${timeId.value}`) as any
if (!dom) return//判断画布是否存在
dom.addEventListener("webglcontextlost", function (event: any) { event.preventDefault(); }, false); //添加丢失上下文处理程序并告诉它阻止默认行为
// 实例化 PAG
const PAG = await PAGInit();
// 获取 PAG 素材数据
const buffer = await fetch(`${urlValue.value}`).then((response) => response.arrayBuffer());
// 加载 PAG 素材为 PAGFile 对象
const pagFile = await PAG.PAGFile.load(buffer);
// 将画布尺寸设置为 PAGFile的尺寸
// dom.width = pagFile.width();
// dom.height = pagFile.height();
// 实例化 PAGView 对象
const pagView = await PAG.PAGView.init(pagFile, dom);
if (pagView) {
pagView.setRepeatCount(0) // 0表示无限循环,大于0表示循环次数
await pagView.play();// 播放 PAGView
}
}
watch(() => props.url, (val) => {
urlValue.value = val
})
onMounted(() => {
nextTick(() => {
initPag()
})
})
</script>
<style>
.pag-size {
/* 根据实际pag动图设置画布尺寸 */
width: 60px;
height: 60px;
position: absolute;
left: 50%;
bottom: -10px;
transform: translateX(-50%);
z-index: 3;
}
</style>
4,在vite.config.js中进行配置,目的是把加载pag文件所需的libpag.wasm复制到项目的dist包中
官网的配置链接源码:pag-web/vue/vue3/vite.config.js at main · libpag/pag-web · GitHub
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import copy from 'rollup-plugin-copy'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
copy({
targets: [
{ src: './node_modules/libpag/lib/libpag.wasm', dest: process.env.NODE_ENV === 'production' ? 'dist/' : 'public/' },
],
hook: process.env.NODE_ENV === 'production' ? 'writeBundle' : "buildStart",
}),
],
base: './',
});
5.使用pag,下面进提供参考
<template>
<div v-if="urlValue">
<pagImg v-if="fileType === 'pag'" :url="generateImgURL(urlValue)" />
<!-- 这里可以兼容svga格式展示,svga的封装,可以看: https://blog.csdn.net/weixin_52663662/article/details/136656519?spm=1001.2014.3001.5501 -->
<!-- <svgaImg v-if="fileType === 'svga'" :url="generateImgURL(urlValue)" /> -->
</div>
</template>
<script lang='ts' setup>
import pagImg from './pagImg.vue'
// import svgaImg from './svgaImg.vue'
import { onMounted, ref, watch } from 'vue'
import { generateImgURL } from '@/utils'; // 我项目封装的路径地址,根据自己需求,获取到完整的pag文件路径
const props = defineProps({
url: {
type: String,
default: '',
}
})
const urlValue = ref(props.url) //https://www.mustake.net/loading.pag
const fileType = ref('') // pag svga
const getExt = (fileUrl: string) => {
// 判断是否是pag文件
if (!fileUrl) { return "" };
// 获取文件后缀名
return fileUrl.split('.').pop()?.toLowerCase() || '';
}
watch(() => props.url, (val) => {
// console.log('pag-->', val);
urlValue.value = val
fileType.value = getExt(val)
})
onMounted(() => {
// console.log('监pag-onMounted->', generateImgURL(urlValue.value));
fileType.value = getExt(urlValue.value)
})
</script>
<style scoped lang='scss'></style>
会有下面问题,在渲染太多后,会报错:
GPU 崩溃导致的。 根据 HandlingContextLost - WebGL Public Wiki 这个问题引擎不太容易处理,建议你们在网页里加个监听,出错后刷新网页。
在上面的报错出现后,会出现pag展示异常的情况,上面的pag组件的封装,我又百度了好久,下面是改良后的写法:
下面是改良后的pag组件封装:
<template>
<div>
<canvas v-if="hasShow" :id="'pag' + timeId" class="pag-size"></canvas>
</div>
</template>
<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { PAGInit } from 'libpag';
const props = defineProps({
url: {
type: String,
default: '',
}
})
const timeId = ref(Math.floor(new Date().getTime() * Math.random())); // 使该图表保持唯一id
const urlValue = ref(props.url) //https://www.mustake.net/loading.pag
const hasShow = ref(true)
const pagDom = ref()
const showPagFn = () => {
const dom = document.getElementById(`pag${timeId.value}`) as any
if (!dom) return//判断画布是否存在
PAGInit().then((PAG) => {
//此处特别要注意一点,你得看你的文件路径是否能够获取到你想要的pag格式文件,如果不行就用../的形式
//一层一层获取,目前在我的操作来看他目前貌似用不了 @/assets/XXX.pag的形式获取到想要的图片路径
//大家可以自行尝试看能否可以获取到对应的pag图片路径
const url = urlValue.value;
fetch(url)
.then((response) => response.blob())
.then(async (blob) => {
const file = new window.File([blob], url.replace(/(.*\/)*([^.]+)/i, '$2'));
const pagFile = await PAG.PAGFile.load(file);
// document.getElementById(`pag${timeId.value}`).width = pagFile.width();
// document.getElementById(`pag${timeId.value}`).height = pagFile.height();
const pagView = await PAG.PAGView.init(pagFile, `#pag${timeId.value}`);
if (pagView) {
pagDom.value = pagView
pagView.setRepeatCount(0);
await pagView.play();
}
});
});
}
watch(() => props.url, (val) => {
urlValue.value = val
})
onMounted(() => {
nextTick(() => {
showPagFn()
})
})
onBeforeUnmount(() => {
if (pagDom.value) {
pagDom.value.pause() // 停止pag展示
}
const canvas = document.getElementById(`pag${timeId.value}`) as any
if (canvas) {
// canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
// 清空画布
// ctx.clearRect(0, 0, canvas.width, canvas.height);
// 手动移除canvas元素(尽管这通常不必要,因为Vue会处理它)
canvas.remove();
}
hasShow.value = false
})
</script>
<style>
.pag-size {
/* 根据实际pag动图设置画布尺寸 */
width: 60px;
height: 60px;
position: absolute;
left: 50%;
bottom: -10px;
transform: translateX(-50%);
z-index: 3;
}
</style>
这样写不会出现内存溢出的问题了,但是还是有警告
怀疑是libpag库源码写法不严谨导致的,这警告目前还没找到解决办法去除,如果有兄弟知道的,请慷慨留言,分享一下