GIS加油站

基于 apng-js 的前端动画实现方案

2025-02-26  本文已影响0人  牛老师讲GIS

概述

基于 apng-js 的前端动画实现方案。

一、前端动画实现方案对比

主流动画实现方式对比:

apng介绍

1.简介

APNG(Animated Portable Network Graphics)是一种基于PNG格式的位图动画扩展,旨在提供比传统GIF更好的图像质量和透明度支持。最早由Mozilla公司在2004年提出,目的是为了替代老旧的GIF格式。尽管PNG组织在2007年否决了APNG成为官方标准的提案,但Mozilla社区继续支持APNG的发展。随着时间的推移,越来越多的软件和浏览器开始支持APNG格式。

2. 技术原理

APNG 通过扩展 PNG 格式实现动画,包含三类关键数据块:

2.2 核心优势

特性 APNG GIF WebP
色彩深度 24位真彩色 8位索引色 24位真彩色
透明度 8位Alpha 1位布尔 8位Alpha
压缩率
兼容性 主流浏览器 全支持 部分浏览器

实现效果

动画.gif

实现代码

1. 安装依赖

npm i apng-js -S

2. 代码实现

将其分装成了一个组件,组件代码如下:

<template>
  <canvas class="apng" ref="canvas"></canvas>
</template>

<script>
import parseAPNG from 'apng-js'

export default {
  props: {
    imgUrl: {
      type: String,
      required: true,
    },
    autoPlay: {
      type: Boolean,
      default: true,
    },
    playbackRate: {
      type: Number,
      default: 1,
    },
    playEnd: {
      type: Function,
      default: () => {},
    },
  },
  data() {
    return {
      player: null,
    }
  },
  mounted() {
    this.initPlayer()
  },
  methods: {
    initPlayer() {
      const that = this
      fetch(this.imgUrl)
        .then(res => res.blob())
        .then(blob => {
          const reader = new FileReader()
          reader.readAsArrayBuffer(blob)
          reader.onload = () => {
            const apng = parseAPNG(reader.result)
            const canvas = that.$refs.canvas
            canvas.width = apng.width
            canvas.height = apng.height
            const ctx = canvas.getContext('2d')
            apng.getPlayer(ctx).then(_player => {
              that.player = _player
              that.player.playbackRate = that.playbackRate // 0-1
              that.player.play()
              that.player.on('end', that.playEnd)
              this.$emit('inited', that.player)
            })
          }
        })
    },
  },
}
</script>
<style scoped lang="scss">
.apng {
  width: 100%;
  height: auto;
}
</style>

页面中调用组件的代码如下:

<template>
  <div class="container">
    <el-button @click="togglePlay">{{ isPlay ? '暂停' : '播放' }}</el-button>
    <div class="bg" @mouseover="play" @mouseout="stop">
      <div class="text">Hello World</div>
      <apng :imgUrl="'/imgs/support.png'" :playEnd="playEnd" @inited="playerInited"></apng>
    </div>
  </div>
</template>

<script>
import Apng from './components/apng.vue';

let player = null

export default {
  components: { Apng },
  data() {
    return {
      isPlay: false,
    }
  },
  methods: {
    playEnd() {
      this.stop()
    },
    playerInited(_player) {
      player = _player
    },
    togglePlay() {
      this.isPlay ? this.stop() : this.play()
      this.isPlay = !this.isPlay
    },
    play() {
      player.play()
      this.isPlay = true
    },
    stop() {
      // player.pause()
      this.isPlay = false
    },
  },
}
</script>

<style scoped lang="scss">
.container {
  padding: 1rem;
}

.bg {
  width: 20rem;
  height: auto;
  position: relative;
  .text {
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 1.2rem;
    width: 100%;
    height: 100%;
  }
}
</style>
上一篇 下一篇

猜你喜欢

热点阅读