Vue3 视频播放与截图功能实现

视频播放

使用 HTML5<video> 标签实现,src 改成你自己的视频路径。

html 复制代码
<video
  ref="videoRef"
  class="video-element"
  src="@/assets/video/1.mp4"
  autoplay
  loop
  muted
></video>

video 标签基本属性

属性 说明
src 视频文件路径(支持相对/绝对路径)
autoplay 自动播放(部分浏览器需配合muted属性)
controls 显示默认播放控制条
width/height 设置视频显示尺寸
muted 静音播放
loop 循环播放
preload 预加载策略(auto/metadata/none)

视频截图功能实现

思路

  1. 视频帧捕获 :首先,通过 <video> 元素获取当前播放的视频帧画面,浏览器会将视频解码为连续的图像帧,我们可以通过 <video> 标签的API访问当前显示的帧。
  2. Canvas 绘制转换 :创建一个与视频尺寸相同的 Canvas 画布,使用 Canvas 2D 上下文(Context2D)的 drawImage() 方法将视频帧绘制到画布上。
  3. Base64 编码输出 :调用 CanvastoDataURL() 方法,将绘制好的图像数据转换为 Base64 编码的图片 URL。该方法支持指定输出格式(如 PNG/JPEG)和质量参数,转换后的数据可以直接用作图片源或下载保存。

代码实现

html 复制代码
<template>
  <div class="video-container">
    <!-- 视频播放器 -->
    <div class="video-wrapper">
      <video
        ref="videoRef"
        class="video-element"
        src="@/assets/video/1.mp4"
        autoplay
        controls
      ></video>
    </div>
  </div>
</template>
javascript 复制代码
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import { ElMessage } from "element-plus";

const videoRef = ref(null);
const screenshotUrl = ref(""); // 截图后的图片URL

// 截图功能
const scanImage = () => {
  if (!videoRef.value) return;

  try {
    // 创建canvas元素
    const canvas = document.createElement("canvas");
    const video = videoRef.value;

    // 设置canvas尺寸与视频相同
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;

    // 绘制当前视频帧到canvas
    const ctx = canvas.getContext("2d");
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

    // 转换为DataURL
    screenshotUrl.value = canvas.toDataURL("image/png");

    ElMessage.success("截图成功!");
  } catch (error) {
    console.error("截图失败:", error);
    ElMessage.error("截图失败: " + error.message);
  }
};

// 快捷键支持 (F9截图)
const handleKeyDown = (e) => {
  if (e.key === "F9") {
    e.preventDefault();
    scanImage();
  }
};

// 添加事件监听
onMounted(() => {
  window.addEventListener("keydown", handleKeyDown);
});

// 移除事件监听
onBeforeUnmount(() => {
  window.removeEventListener("keydown", handleKeyDown);
});
</script>
scss 复制代码
<style lang="scss" scoped>
.video-container {
  padding: 20px;
  max-width: 800px;
  margin: 0 auto;
}

.video-wrapper {
  position: relative;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  background: #000;
}

.video-element {
  width: 100%;
  display: block;
}

.screenshot-controls {
  position: absolute;
  bottom: 20px;
  right: 20px;
  z-index: 10;
}

.screenshot-result {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 300px;
}

.screenshot-image {
  max-width: 100%;
  border: 1px solid #ebeef5;
  border-radius: 4px;
}

.empty-tip {
  color: #909399;
  font-size: 14px;
  text-align: center;
  padding: 20px;
}
</style>
相关推荐
拉不动的猪15 分钟前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪24 分钟前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
uhakadotcom2 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom2 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom2 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom2 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试
咖啡教室3 小时前
前端开发日常工作每日记录笔记(2019至2024合集)
前端·javascript
咖啡教室3 小时前
前端开发中JavaScript、HTML、CSS常见避坑问题
前端·javascript·css
市民中心的蟋蟀6 小时前
第五章 使用Context和订阅来共享组件状态
前端·javascript·react.js
逆袭的小黄鸭6 小时前
JavaScript 闭包:强大特性背后的概念、应用与内存考量
前端·javascript·面试