vue3展示pag格式动态图

提示:如果是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库源码写法不严谨导致的,这警告目前还没找到解决办法去除,如果有兄弟知道的,请慷慨留言,分享一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值