vue2前端使用图片展现视频,无法销毁请求

实现思路,使用canvas绘制图像,然后使用动画帧刷新页面

javascript 复制代码
<template>
  <canvas ref="imageCanvas" :style="canvasStyle"></canvas>
</template>

<script>
export default {
  props: {
    info: {
      type: Object,
      default: () => ({ url: '', index: '' }),
    },
  },
  data() {
    return {
      currentImage: null,
      isFullScreen: false,
      canvas: null,
      ctx: null,
      canvasStyle: {
        height: '100%',
        width: '100%',
        cursor: 'pointer',
        transition: 'transform 0.3s ease-in-out',
      },
      animationFrameId: null,
    };
  },
  mounted() {
    this.initCanvas();
    this.startAnimation();
    this.addEventListeners();
  },
  watch: {
    'info.url'(newVal) {
      if (newVal) {
        this.loadImage();
      }
    },
  },
  beforeDestroy() {
    this.stopAnimation();
    this.destroyCanvas();
    this.destroyImage();
    this.removeEventListeners();
  },
  methods: {
    initCanvas() {
      this.canvas = this.$refs.imageCanvas;
      this.ctx = this.canvas.getContext('2d');
    },
    loadImage() {
      if (!this.info || !this.info.url) return;

      this.currentImage = new Image();
      this.currentImage.onload = () => {
        this.drawCanvas();
      };
      this.currentImage.src = this.info.url;
    },
    drawCanvas() {
      if (this.currentImage) {
        this.canvas.width = this.currentImage.width;
        this.canvas.height = this.currentImage.height;
        this.ctx.drawImage(this.currentImage, 0, 0, this.canvas.width, this.canvas.height);
      }
    },
    startAnimation() {
      const animate = () => {
        this.loadImage();
        this.animationFrameId = requestAnimationFrame(animate);
      };
      this.animationFrameId = requestAnimationFrame(animate);
    },
    stopAnimation() {
      if (this.animationFrameId) {
        cancelAnimationFrame(this.animationFrameId);
        this.animationFrameId = null;
      }
    },
    addEventListeners() {
      if (this.canvas) {
        this.canvas.addEventListener('dblclick', this.toggleFullscreen);
      }
      document.addEventListener('fullscreenchange', this.handleFullscreenChange);
    },
    removeEventListeners() {
      if (this.canvas) {
        this.canvas.removeEventListener('dblclick', this.toggleFullscreen);
      }
      document.removeEventListener('fullscreenchange', this.handleFullscreenChange);
    },
    toggleFullscreen() {
      if (!this.isFullScreen) {
        if (this.canvas.requestFullscreen) {
          this.canvas.requestFullscreen();
        } else if (this.canvas.mozRequestFullScreen) {
          this.canvas.mozRequestFullScreen();
        } else if (this.canvas.webkitRequestFullscreen) {
          this.canvas.webkitRequestFullscreen();
        } else if (this.canvas.msRequestFullscreen) {
          this.canvas.msRequestFullscreen();
        }
      } else {
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.mozCancelFullScreen) {
          document.mozCancelFullScreen();
        } else if (document.webkitExitFullscreen) {
          document.webkitExitFullscreen();
        } else if (document.msExitFullscreen) {
          document.msExitFullscreen();
        }
      }
    },
    handleFullscreenChange() {
      this.isFullScreen = !this.isFullScreen;
      if (this.isFullScreen) {
        this.canvasStyle = {
          position: 'fixed',
          top: '0',
          left: '0',
          width: '100vw',
          height: '100vh',
          backgroundColor: 'rgba(0, 0, 0, 0.9)',
          cursor: 'default',
          objectFit: 'contain',
          objectPosition: 'center',
          transition: 'transform 0.3s ease-in-out',
          zIndex: 9999,
        };
        document.body.style.overflow = 'hidden';
      } else {
        this.canvasStyle = {
          height: '100%',
          width: '100%',
          cursor: 'pointer',
          transition: 'transform 0.3s ease-in-out',
        };
        document.body.style.overflow = 'auto';
      }
    },
    destroyCanvas() {
      if (this.canvas) {
        this.canvas.width = 0;
        this.canvas.height = 0;
        this.ctx = null;
        this.canvas = null;
      }
    },
    destroyImage() {
      if (this.currentImage) {
        this.currentImage.onload = null;
        this.currentImage.onerror = null;
        this.currentImage.src = '';
        this.currentImage = null;
      }
    },
  },
};
</script>

<style scoped>
/* 可以根据需要添加 scoped 样式 */
</style>
相关推荐
风骏时光牛马6 分钟前
大模型底层架构与推理机制源码深度剖析
前端
java1234_小锋5 小时前
【技术专题】HTML5 网页技术 - HTML5 Canvas 基础以及动画入门
前端·html·html5
知了学历孙老师8 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
2601_9654542310 小时前
做新闻视频没素材?AI按文稿语义自动配画面的工作流
音视频
ShineWinsu10 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
福兮说11 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
程序员老赵13 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
前端·docker·开源
Swot13 小时前
Asciidoctor 公式数字下标错位问题:原因分析与解决方案
前端
Swot13 小时前
leo-editor 中将 Markdown 内容转成 asciidoc 格式
前端
狒狒AI13 小时前
Remotion / GSAP+Three / HyperFrames / Skia 四栈实测:代码渲染知识视频的选栈方法(附开源技能)
前端·人工智能·aigc