video组件封装

video封装ui videoui无任何依赖,代码注释很清楚。 立即下载
<template>
  <div class="video-container" :style="containerStyle">
    <video
      ref="videoRef"
      class="video-player"
      :width="width"
      :height="height"
      :poster="poster"
      :autoplay="autoplay"
      :loop="loop"
      :muted="muted"
      :controls="showControls"
      :preload="preload"
      @play="onPlay"
      @pause="onPause"
      @ended="onEnded"
      @timeupdate="onTimeUpdate"
      @volumechange="onVolumeChange"
      @error="onError"
    >
      <source v-for="source in sources" :key="source.src" :src="source.src" :type="source.type" />
      您的浏览器不支持 HTML5 视频标签。
    </video>
    
    <!-- 自定义控制条(可选) -->
    <div v-if="customControls" class="custom-controls">
      <button @click="togglePlay">
        {{ isPlaying ? '暂停' : '播放' }}
      </button>
      <input
        type="range"
        min="0"
        :max="duration"
        v-model="currentTime"
        @input="seek"
      />
      <button @click="toggleMute">
        {{ isMuted ? '取消静音' : '静音' }}
      </button>
      <input
        type="range"
        min="0"
        max="1"
        step="0.01"
        v-model="volume"
        @input="changeVolume"
      />
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted } from 'vue'

const props = defineProps({
  // 视频源,支持多个源格式
  sources: {
    type: Array,
    required: true,
    validator: (value) => {
      return value.every(source => source.src && source.type)
    }
  },
  // 视频宽度
  width: {
    type: [String, Number],
    default: '100%'
  },
  // 视频高度
  height: {
    type: [String, Number],
    default: 'auto'
  },
  // 封面图
  poster: {
    type: String,
    default: ''
  },
  // 是否自动播放
  autoplay: {
    type: Boolean,
    default: false
  },
  // 是否循环播放
  loop: {
    type: Boolean,
    default: false
  },
  // 是否静音
  muted: {
    type: Boolean,
    default: false
  },
  // 是否显示原生控制条
  showControls: {
    type: Boolean,
    default: true
  },
  // 预加载方式
  preload: {
    type: String,
    default: 'auto',
    validator: (value) => ['auto', 'metadata', 'none'].includes(value)
  },
  // 是否使用自定义控制条
  customControls: {
    type: Boolean,
    default: false
  },
  // 容器样式
  containerStyle: {
    type: Object,
    default: () => ({})
  }
})

const emit = defineEmits([
  'play',
  'pause',
  'ended',
  'timeupdate',
  'volumechange',
  'error',
  'ready'
])

const videoRef = ref(null)
const isPlaying = ref(false)
const isMuted = ref(props.muted)
const duration = ref(0)
const currentTime = ref(0)
const volume = ref(props.muted ? 0 : 1)

// 初始化视频
onMounted(() => {
  if (videoRef.value) {
    // 确保muted属性与props同步
    videoRef.value.muted = props.muted
    isMuted.value = props.muted
    
    // 获取视频时长
    const updateDuration = () => {
      duration.value = videoRef.value.duration || 0
    }
    
    videoRef.value.addEventListener('loadedmetadata', updateDuration)
    videoRef.value.addEventListener('durationchange', updateDuration)
    
    emit('ready', videoRef.value)
  }
})

// 播放/暂停切换
const togglePlay = () => {
  if (!videoRef.value) return
  
  if (isPlaying.value) {
    videoRef.value.pause()
  } else {
    videoRef.value.play()
  }
}

// 跳转到指定时间
const seek = () => {
  if (videoRef.value) {
    videoRef.value.currentTime = currentTime.value
  }
}

// 音量调整
const changeVolume = () => {
  if (videoRef.value) {
    videoRef.value.volume = volume.value
    isMuted.value = volume.value === 0
  }
}

// 静音切换
const toggleMute = () => {
  if (videoRef.value) {
    videoRef.value.muted = !isMuted.value
    isMuted.value = !isMuted.value
    if (!isMuted.value) {
      volume.value = videoRef.value.volume
    }
  }
}

// 事件处理
const onPlay = () => {
  isPlaying.value = true
  emit('play')
}

const onPause = () => {
  isPlaying.value = false
  emit('pause')
}

const onEnded = () => {
  isPlaying.value = false
  emit('ended')
}

const onTimeUpdate = () => {
  if (videoRef.value) {
    currentTime.value = videoRef.value.currentTime
    emit('timeupdate', currentTime.value)
  }
}

const onVolumeChange = () => {
  if (videoRef.value) {
    volume.value = videoRef.value.volume
    isMuted.value = videoRef.value.muted
    emit('volumechange', {
      volume: volume.value,
      muted: isMuted.value
    })
  }
}

const onError = () => {
  if (videoRef.value) {
    emit('error', videoRef.value.error)
  }
}

// 暴露方法给父组件
defineExpose({
  play: () => videoRef.value?.play(),
  pause: () => videoRef.value?.pause(),
  togglePlay,
  toggleMute,
  seek,
  setVolume: (val) => {
    if (videoRef.value) {
      videoRef.value.volume = val
      volume.value = val
    }
  },
  getVideoElement: () => videoRef.value
})
</script>

<style scoped>
.video-container {
  position: relative;
  display: inline-block;
  line-height: 0;
}

.video-player {
  max-width: 100%;
  height: auto;
  display: block;
  background-color: #000;
}

.custom-controls {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.5);
  padding: 10px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.custom-controls button {
  background: #fff;
  border: none;
  padding: 5px 10px;
  border-radius: 3px;
  cursor: pointer;
}

.custom-controls input[type="range"] {
  flex-grow: 1;
}
</style>

使用

<template>
  <div>
    <VideoPlayer
      :sources="[
        { src: 'https://example.com/video.mp4', type: 'video/mp4' },
        { src: 'https://example.com/video.webm', type: 'video/webm' }
      ]"
      poster="https://example.com/poster.jpg"
      :autoplay="false"
      :loop="false"
      :customControls="true"
      @play="handlePlay"
      @pause="handlePause"
      ref="videoPlayer"
    />
    
    <button @click="$refs.videoPlayer.togglePlay()">外部控制播放/暂停</button>
  </div>
</template>

<script setup>
import VideoPlayer from './components/VideoPlayer.vue'

const handlePlay = () => {
  console.log('视频开始播放')
}

const handlePause = () => {
  console.log('视频暂停')
}
</script>

video的原生制作 关于h5的video开发,详细请下载观看。 立即下载

相关推荐

RAID 0/1/5/10 性能实测:4块 SATA SSD 组阵列,顺序读写速度对比

本文通过实测对比了RAID 0/1/5/10在4块SATA SSD上的顺序读写性能,详细展示了不同RAID级别的配置方法、理论性能与实际测试数据。测试结果显示,RAID 0在顺序读写速度上表现最佳,而RAID 10则在性能与数据安全之间取得了平衡,适合数据库服务器等关键应用场景。

weixin_33462167的博客 424

【vue video.js】 video.js视频组件的封装,可复制使用

video.js视频组件的封装,可复制使用

weixin_41747256的博客 832

论文理解【LLM-OR】——【OptiMUS】Scalable Optimization Modeling with (MI)LP Solvers and Large Language Models

OptiMUS 把“自然语言→优化建模与求解”从单次生成改造成“结构化问题 + 多智能体协作 + 连接图检索”的模块化流程,并在更长更难的数据集上验证了这种结构化方法相对端到端 prompting 的优

佚失的诗篇 823

如何封装个video插件。自定义进度条点击拖拽,播放暂停,播放倍速

vue3开发嵌入式,播放器在浏览器中是正常的。但嵌入到app里,app不适配,无法全屏,无法设置倍速,controls在视频播放时点击视频无法弹出。

tree_ge的博客 2598

CPRI原理及应用--帧结构

对于CPRI 控制字,协议将1个超帧(256基本帧)的控制数据划分为一个“子通道”,将子通道内超帧内的控制字进行行列划分,分为4列X64行,每64个基本帧组成1列。如下图所示。每个Xs子通道内Ns的定义基本相同,在做控制字设计时,主要已Xs和Ns和X.Y.Z开展控制字映射。

u014035968的博客 2325

RTAB-map:实时高效的SLAM库

Real‐time appearance‐based mapping (RTAB‐Map)是一种基于外观的闭环检测方法,具有良好的内存管理,以满足处理大场景和在线长周期管理要求。RTAB‐Map集成了视觉和激光雷达SLAM方案,并支持目前绝大多数的传感器 是一个强大的、开源的Simultaneous Localization and Mapping(SLAM)库,专为机器人和无人驾驶领域设计。它提供了一套完整的解决方案,用于构建三维地图,并在未知环境中进行实时定位与导航。 github项目地址 RTAB-

weixin_45761399的博客 1万+

HTML5的Video标签的属性,方法和事件汇总

标签的属性 src :视频的属性 poster:视频封面,没有播放时显示的图片 preload:预加载 autoplay:自动播放 loop:循环播放 controls:浏览器自带的控制条 width:视频宽度 height:视频高度 html 代码 <<span class="hljs-title" style="color: ...

lxw1844912514的博客 2027

树莓派上基于ONNXRuntime与Qt的C++模型部署实战指南

本文详细介绍了在树莓派上使用ONNXRuntime与Qt进行C++模型部署的完整流程。从环境配置、依赖安装到交叉编译优化,再到Qt界面集成与ARM架构性能调优,提供了实战指南和常见问题解决方案,帮助开发者高效完成边缘设备上的AI应用部署。

ik6789012的博客 339

Vue2 video播放器封装(支持七项功能)

自己根据html原生的video播放器,在原有基础上封装了多项功能,包括①录制(含录制计时器)②截图③全屏放大④播放/暂停⑤倍速功能(样式需要自己写,我的样式写在了别的页面)⑥音量调节/静音⑦计算缓冲速度。npm install html2canvas (截图用到的插件)npm install RecordRTC (rtc录制插件)

w1426154928的博客 1354

简单易懂的AXI_Lite 总线详解

简单易懂的AXI_Lite 总线详解 1、前言 AXI_LITE协议主要应用于Xilinx的ZYNQ芯片构架下的ARM和FPGA之间的数据读写,更偏向于单个寄存器的读写。 2、AXI总线与ZYNQ的关系 AXI(Advanced eXtensible Interface)本是由ARM公司提出的一种总线协议,Xilinx从6系列的FPGA开始对AXI总线提供支持,此时AXI已经发展到了AXI4这个版本,所以当你用到Xilinx的软件的时候看到的都是“AIX4”的IP,如Vivado打包一个AXI IP的时候,

m0_46642108的博客 8495

一张图看懂 ABAP CDS 两大子语言:CDS DDL 与 CDS DCL 以及缺席的 DML

ABAP CDS 的核心设计思想围绕语义数据模型(DDL)与数据访问控制(DCL)展开,而非单纯作为SQL查询工具。其DDL通过声明式语法定义业务导向的数据视图,强调模型稳定性与复用性;DCL则将访问控制逻辑下沉到模型层,实现行级权限过滤。ABAP CDS刻意剥离DML功能,交由ABAP SQL处理数据变更,形成清晰的分层架构。这种设计使数据定义、访问控制与应用逻辑解耦,为现代ABAP应用提供更安全、可维护的数据治理方案。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 976

【Vue-video】Video 封装组件-Copy直接用&解决封装BUG

只要注意以上几个点,你封装的组件绝对不会出现什么基本的 BUG。 如果你自己自定义组件操作布局,那就是你的另外的事情咯! 好啦~就这样!

学习只为当小狗狗,学习只为当小狗狗,学习只为当小狗狗,学习只为当小狗狗,学习只为当小狗狗,学习只为当小狗狗,学习只为当小狗狗 609

ANSYS Fluent:湍流模型理论与应用

雷诺平均方程(RANS,Reynolds-Averaged Navier-Stokes equations)是湍流建模中最常用的方法。它通过将Navier-Stokes方程中的瞬时速度分解为平均速度和脉动速度,然后对这些方程进行时间平均,从而简化了湍流的计算。RANS方法的关键在于湍流闭合问题的解决,即如何准确地表示脉动速度的统计量。雷诺应力模型(RSM)是一种更高级的湍流模型,它通过求解六个雷诺应力方程来描述湍流的各向异性。RSM模型能够更准确地预测复杂的湍流流动,如旋转流和分离流,但计算成本较高。

kkchenjj的博客 2946

小程序video封装组件时获取video节点的方法

小程序video封装组件时获取video节点的方法 #js# 1、在compont上方定义一个全局的空变量,用来承载video标签节点 let videoCtx = null Component({ ... 2、在attached周期里进行获取(这是重点,否则获取不到) lifetimes: { attached: function() { videoCtx = wx.c...

尹小姐的博客 1454

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Vue3封装Video.js组件(基于video.js)

Vue3封装Video.js组件(基于video.js)

pizixian_的博客 3644

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

video基础介绍&封装react-video基础组件,ES6

  好几个月没有写博客了,人都赖了,今天抽了一点时间把最近项目react中video整理了一下(感觉这个以后用的活比较多)   1.前三部部分详细归纳了video的基础知识,属性和功能;   2.第四部分是封装了一个video基础组件,所有事件都采用对外开放状态,在引入时可以直接书写用,小伙伴们可以直接参考example,对于其他属性比如是否采用浏览器控制条等,可以结合前三部分的梳理自己重新书...

weixin_30343157的博客 552

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

vue封装video组件(基于chimee)

vue封装video组件

pizixian_的博客 669

react封装一个公用的video组件(video-react)

预览: 1、cnpm install --save video-react react react-dom 2、js代码(复制即用) import React, { Component } from 'react'; import { Player, ControlBar } from 'video-react'; import './index.less'; /** * 视频播放组件 ...

张鹏~IT~少年人的博客 4632

vue3封装的video组件

【代码】vue3封装的video组件。

weixin_45458830的博客 1128

vue中实现 【 Video视频进度条不能拖动,且能倍速播放 】,用vue-video-player插件,封装成组件的方法步骤

一、安装vue-video-player 插件 npm install vue-video-player -S 二、引入 1、全局引入,main.js import VideoPlayer from 'vue-video-player' import 'vue-video-player/src/custom-theme.css' import 'video.js/dist/video-js.css' Vue.use(VideoPlayer) 2、局部引入 import { vide...

weixin_50450473的博客 1万+

Vue 3 中优雅地集成 Video.js 播放器:从组件封装到功能定制

Vue 3 中优雅地集成 Video.js 播放器:从组件封装到功能定制

studying... 553

vue封装video组件(基于flv)

vue封装video组件

pizixian_的博客 842

vue-video-group-component基于(vue2) element-ui 与 LivePlayer H5 播放器二次封装的视频组组件

之前感兴趣好久,一直想封装一个组件发布,空闲下来了试了一下,感觉还是不难的,比较简单,就不贴代码了。

weixin_44899321的博客 850

Vue2 封装 Video 视频播放组件

Vue2 封装 Video 视频播放组件

FitnessSnail的博客 3177

react + video标签,自定义视频控制栏controls,封装成完整组件,附带完整代码

本文介绍了自定义video标签控制栏的必要性和实现方法。原生控制栏存在样式不可定制、功能局限和移动端兼容性差等问题。作者基于React实现了一个功能丰富的自定义控制栏,包含画中画、静音、全屏、进度条等控件,并解决了自动播放限制等技术难点。文章详细展示了代码实现,包括事件处理、状态管理和跨浏览器兼容方案。最后强调浏览器对自动播放的严格限制,建议开发者遵循用户交互原则,避免在无交互情况下强制视频播放。该组件实现了统一风格和功能扩展,为视频播放开发提供了实用参考。

qq_37057426的博客 877
上一篇: 一个丝滑的页面上下滚动效果
下一篇: Vue3 打印网页内容
irisMoon06
博客等级 码龄5年 280粉丝 150原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值