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>
相关推荐
mCell18 分钟前
JavaScript 的多线程能力:Worker
前端·javascript·浏览器
超级无敌攻城狮2 小时前
3 分钟学会!波浪文字动画超详细教程,从 0 到 1 实现「思考中 / 加载中」高级效果
前端
excel3 小时前
用 TensorFlow.js Node 实现猫图像识别(教学版逐步分解)
前端
gnip3 小时前
JavaScript事件流
前端·javascript
赵得C3 小时前
【前端技巧】Element Table 列标题如何优雅添加 Tooltip 提示?
前端·elementui·vue·table组件
wow_DG3 小时前
【Vue2 ✨】Vue2 入门之旅 · 进阶篇(一):响应式原理
前端·javascript·vue.js
weixin_456904273 小时前
UserManagement.vue和Profile.vue详细解释
前端·javascript·vue.js
资深前端之路3 小时前
react 面试题 react 有什么特点?
前端·react.js·面试·前端框架
aaaweiaaaaaa3 小时前
HTML和CSS学习
前端·css·学习·html
秋秋小事4 小时前
React Hooks useContext
前端·javascript·react.js