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>
相关推荐
熊猫钓鱼>_>4 小时前
动态网站发布部署核心问题详解
前端·nginx·容器化·网页开发·云服务器·静态部署
方也_arkling4 小时前
elementPlus按需导入配置
前端·javascript·vue.js
我的xiaodoujiao4 小时前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 44--将自动化测试结果自动推送至钉钉工作群聊
前端·python·测试工具·ui·pytest
沛沛老爹4 小时前
Web开发者转型AI:多模态Agent视频分析技能开发实战
前端·人工智能·音视频
David凉宸4 小时前
vue2与vue3的差异在哪里?
前端·javascript·vue.js
笔画人生4 小时前
Cursor + 蓝耘API:用自然语言完成全栈项目开发
前端·后端
AC赳赳老秦5 小时前
外文文献精读:DeepSeek翻译并解析顶会论文核心技术要点
前端·flutter·zookeeper·自动化·rabbitmq·prometheus·deepseek
小宇的天下5 小时前
Calibre 3Dstack --每日一个命令day18【floating_trace】(3-18)
服务器·前端·数据库
等风来不如迎风去5 小时前
【UniVA】1:统一的视频agent:智能体系统,专门用于处理复杂的视频生成、编辑和理解任务
音视频
毕设源码-钟学长5 小时前
【开题答辩全过程】以 基于web技术的酒店信息管理系统设计与实现-为例,包含答辩的问题和答案
前端