0


video 自定义视频播放控件

ui设计的界面总是极具个性化的,要去修改插件中的视频控件的样式和布局太困难了,那就自己参照video原生事件,重写一个吧。

(效果图预览)


一、video标签的属性(props)

html 标签 | 菜鸟教程

  1. <video
  2. ref="videoPlayer"
  3. id="videoElement"
  4. controls
  5. autoplay
  6. :muted="isMute"
  7. width="800px"
  8. height="600px"
  9. >
  10. 您的浏览器不支持video
  11. </video>

参数说明:(更多属性参照上述菜鸟教程中的video标签)

  • controls:默认为true,即向用户展示视频控件(如播放、暂停按钮等)
  • autoplay:如果出现该属性,则视频在就绪后马上播放。
  • muted:是否静音,默认为true
  • width:设置视频播放器的宽度

二、video视频控件的触发事件

video标签支持的多媒体事件(Media Events) | 菜鸟教程

  1. <video
  2. ref="videoPlayer"
  3. id="videoElement"
  4. controls
  5. autoplay
  6. :muted="isMute"
  7. width="100%"
  8. height="100%"
  9. @loadeddata="setVideoPoster($event)"
  10. @progress="videoProgress($event)"
  11. @pause="videoPause($event)"
  12. @play="videoPlay($event)"
  13. @timeupdate="videoTimeUpdate()"
  14. @ended="videoEnded()"
  15. @contextmenu="contextmenu"
  16. >
  17. 您的浏览器不支持video
  18. </video>
  19. <button @click="handlePlay">播放</button>
  20. <button @click="handlePause">暂停</button>
  21. <button @click="handleMute">切换静音</button>
  22. <button @click="fullScreen">全屏</button>
  23. data(){
  24. return{
  25. isMute: true // 默认静音
  26. }
  27. }

1、播放(onplay事件)

this.$refs.videoPlayer.play();

  1. methods:{
  2. // 视频要开始播放时
  3. videoPlay(e){
  4. // ...触发该函数后视频会开始播放,我们可以做一些想做的事情,比如改变自定义播放按钮的样式等
  5. },
  6. // 自定义播放按钮中,触发视频的播放事件
  7. handelPlay(){
  8. this.$refs.videoPlayer.play(); // 会触发videoPlay()函数
  9. }
  10. }

2、暂停(onpause事件)

this.$refs.videoPlayer.pause();

  1. methods:{
  2. // 视频要暂停播放时
  3. videoPause(e){
  4. // ...触发该函数后视频会暂停播放
  5. },
  6. // 自定义播放按钮中,触发视频的播放事件
  7. handelPause(){
  8. this.$refs.videoPlayer.pause(); // 会触发videoPause()函数
  9. }
  10. }

3、静音(muted属性)

(1)切换静音

// 手动切换静音(点击(非拖拽)静音时,用户选择的音量不变)

handleMute() {

  1. this.isMute = !this.isMute;

},

(2)改变音量(volume属性

this.$refs.videoPlayer.volume = a; (a为从 0~1的数字)

  1. // 这里用element的进度条写音量大小调节条
  2. <el-slider v-model="curVolume" :show-tooltip="false" @input="changeVolume"></el-slider>
  3. data(){
  4. return{
  5. curVolume: 0, // 默认音量为0
  6. }
  7. },
  8. methods:{
  9. changeVolume(val){
  10. this.curVolume = val;
  11. // 由于h5规定volum的值在0-1之间,所以这里要对获取到的val做一个处理(滑块的val是从0-100)
  12. this.$refs.videoPlayer.volume = val / 100;
  13. // 音量为0的时候,video控件为静音
  14. if ( val == 0 ) {
  15. this.isMute = true;
  16. } else {
  17. this.isMute = false;
  18. }
  19. }
  20. }

4、全屏

  1. fullScreen() {
  2. this.$refs.videoPlayer.webkitRequestFullScreen();
  3. },

5、播放进度条

获取视频总时长(duration)

var videoObj = this.$refs.videoPlayer;

videoObj.addEventListener('canplay', () => {

  1. this.totalT = videoObj.**duration**;

})

获取视频加载进度

HTML5视频 - 加载百分比?

HTML5视频 - 加载百分比?

  1. // 获取视频加载进度videoProgress(e){
  2. var bf = this.$refs.videoPlayer.buffered;
  3. var time = this.$refs.videoPlayer.currentTime;
  4. if ( bf.length != 0 ){
  5. var range = 0;
  6. while( !( bf.start(range) <= time && time <= bf.end(range) ) ) {
  7. range += 1;
  8. }
  9. var loadEndPercentage = ( bf.end(range) / this.playerVideo.duration ) * 100; // 结束加载的百分比
  10. this.persentLoad = loadEndPercentage;
  11. }
  12. },

(1)父组件调用

  1. <template>
  2. <videoref="videoPlayer"
  3. @progress="videoProgress($event)"
  4. @timeupdate="videoTimeUpdate()"
  5. >
  6. 您的浏览器不支持video
  7. </video>// 视频播放、加载进度条<ProgressLine:presentT="presentT":totalT="totalT":persentLoad="persentLoad"
  8. @changeCurrentTime="changeCurrentTime($event)"
  9. @changeCurrentWord="changeCurrentWord($event)"
  10. ></ProgressLine>// 播放时长、视频总时长<p><spanid="currentTime"ref="progressTimer">{{ videoCurrentTime }}</span><spanstyle="color: #ffffff;opacity: 0.3;">&nbsp;/&nbsp;</span><spanid="durationTime"ref="durationTimer">{{ videoTotalTime }}</span></p>
  11. </template>
  12. importProgressLinefrom'./ProgressLine.vue';
  13. exportdefault {
  14. name: 'videoPage',
  15. components: {
  16. ProgressLine
  17. },
  18. data(){
  19. return{
  20. presentT: 0, // 进度条的当前值,必须为numbertotalT: 0, // 进度条的最大值,必须为numberpersentLoad: 0, // 视频加载进度 videoCurrentTime: '00:00', // 当前视频已播放时长videoTotalTime: '00:00', // 视频总时长
  21. }
  22. },
  23. methods:{
  24. // 子组件传入的时间修改changeCurrentTime(data) {
  25. this.$refs.videoPlayer.currentTime = data; // 点击进度条设置视频当前播放点
  26. },
  27. changeCurrentWord(data) {
  28. this.videoCurrentTime = this.formatTime(data); // 当前播放时间显示文字
  29. },
  30. // 获取视频加载进度videoProgress(e){
  31. var bf = this.playerVideo.buffered;
  32. var time = this.playerVideo.currentTime;
  33. if ( bf.length != 0 ){
  34. var range = 0;
  35. while( !( bf.start(range) <= time && time <= bf.end(range) ) ) {
  36. range += 1;
  37. }
  38. var loadEndPercentage = ( bf.end(range) / this.playerVideo.duration ) * 100; // 结束加载的百分比this.persentLoad = loadEndPercentage;
  39. }
  40. },
  41. // 视频自动播放时videoTimeUpdate(){
  42. this.presentT = this.playerVideo.currentTime; // 获取当前播放时长this.videoCurrentTime = this.formatTime(this.presentT); // 时间格式化
  43. },
  44. // 时间格式化formatTime(t) {
  45. var m = parseInt(t % 3600 / 60)
  46. m = m < 10 ? '0' + m : m
  47. var s = parseInt(t % 60)
  48. s = s < 10 ? '0' + s : s
  49. return m + ':' + s
  50. },
  51. }
  52. }

(2)进度条组件(播放进度条 和 加载进度条)

  1. // ProgressLine.vue 进度条组件
  2. <template>
  3. <div><divclass="line-background"><divclass="time-line" @click="adjustProgress($event)"><divclass="progress-round"ref="progressRound"><divclass="loading"ref="persentLoad"style="width: 0;"></div><!-- 加载进度条 --><divclass="progress"ref="progress" @click="adjustProgress"></div><divclass="round"ref="round" @mousedown="roundDrag"></div></div></div></div></div>
  4. </template>
  5. <script>exportdefault {
  6. name: 'ProgressLine',
  7. props: {
  8. presentT: {},
  9. totalT: {},
  10. persentLoad: { default : 0 }
  11. },
  12. data() {
  13. return {
  14. // 进度条拖拽dragClick: false,
  15. // 鼠标/手指按下clickDown: false,
  16. }
  17. },
  18. created() {
  19. },
  20. watch: {
  21. // 侦听当前播放时长设置进度条presentT: {
  22. handler(newValue, oldValue) {
  23. // 未点击进度条if (this.dragClick == false && this.clickDown == false) {
  24. this.$refs.progress.style.width = newValue / this.totalT * 100 + '%'if ((newValue / this.totalT * 100 - 1.23) < 0) {
  25. this.$refs.round.style.left = 0 + '%'
  26. } else {
  27. this.$refs.round.style.left = (newValue / this.totalT * 100) - 1.23 + '%'
  28. }
  29. } elseif (this.dragClick == true) {
  30. this.dealWidth()
  31. this.dragClick = false
  32. }
  33. }
  34. },
  35. persentLoad: {
  36. handler(newValue, oldValue) {
  37. this.$refs.persentLoad.style.width = ( newValue / 100 ) * 1300 + 'px';
  38. }
  39. }
  40. },
  41. methods: {
  42. progressData(data) {
  43. this.$emit('changeCurrentTime', data)
  44. this.$emit('changeCurrentWord', data)
  45. },
  46. // 进度条位置和圆点定位处理dealWidth() {
  47. this.$refs.progress.style.width = this.progressWidth / this.$refs.progressRound.offsetWidth * 100 + '%'if ((this.progressWidth / this.$refs.progressRound.offsetWidth * 100) - 1.23 < 0) { // 圆点定位this.$refs.round.style.left = 0 + '%'
  48. } else {
  49. this.$refs.round.style.left = (this.progressWidth / this.$refs.progressRound.offsetWidth * 100) - 1.23 + '%'
  50. }
  51. },
  52. // 进度条点击adjustProgress(e) {
  53. this.dragClick = true
  54. e.preventDefault()
  55. const { left, width } = this.$refs.progressRound.getBoundingClientRect() // 进度条到屏幕距离及进度条的宽度this.progressWidth = e.clientX - left
  56. if (this.progressWidth < 0) {//进度条边界值计算情况this.progressWidth = 0
  57. } elseif (this.progressWidth >= width) {
  58. this.progressWidth = width
  59. } else {
  60. this.progressWidth = e.clientX - left // e.clientX:鼠标点击的位置到屏幕最左侧的距离
  61. }
  62. this.dealWidth()
  63. this.progressData((this.progressWidth / width) * this.totalT)
  64. },
  65. // 进度条圆点拖拽roundDrag(event) {
  66. event.preventDefault()
  67. const offsetX = event.offsetXthis.dragClick = truethis.clickDown = true// 解决圆点拖拽进度条长度抖动document.onmousemove = (e) => { // 给圆点添加移动事件
  68. e.preventDefault()// 阻止进度条拖拽时屏幕原有的滑动功能const X = e.clientX// 获取圆点离屏幕的距离const { left, width } = this.$refs.progressRound.getBoundingClientRect()
  69. const ml = X - left // 进度条长度:圆点离屏幕的距离减去进度条最左边离屏幕的距离if (ml <= 0) { // 进度条长度最小和最大值的界定this.progressWidth = 0
  70. } elseif (ml >= width) {
  71. this.progressWidth = width
  72. } else {
  73. this.progressWidth = ml
  74. }
  75. this.progressData((this.progressWidth / width) * this.totalT) //视频播放时间this.dealWidth()
  76. }
  77. // 抬起鼠标,结束移动事件document.onmouseup = () => {
  78. document.onmousemove = nulldocument.onmouseup = nullthis.clickDown = false
  79. }
  80. },
  81. }
  82. }
  83. </script><stylelang="less"scoped>.line-background {
  84. width: 100%;
  85. height: 10px;
  86. background-color: rgba(255, 255, 255, 0.3);
  87. .time-line {
  88. width: 100%;
  89. height: 10px;
  90. background-color: #565651;
  91. .progress-round {
  92. cursor: pointer;
  93. width: 100%;
  94. position: relative;
  95. display: flex;
  96. .loading {
  97. height: 10px;
  98. background-color: rgba(255, 255, 255, 0.3);
  99. }
  100. .progress {
  101. position: absolute;
  102. top: 0;
  103. left: 0;
  104. width: 00%;
  105. height: 10px;
  106. background-color: #3d7eff;
  107. }
  108. .round {
  109. position: absolute;
  110. top: 50%;
  111. left: 0;
  112. transform: translateY(-50%);
  113. width: 16px;
  114. height: 16px;
  115. border-radius: 16px;
  116. background: #ffffff;
  117. box-shadow: -2px0px2px2pxrgba(3, 0, 0, 0.30);
  118. }
  119. }
  120. }
  121. }
  122. </style>

6、视频中禁用右键(可以禁止用户下载视频)

  1. // 在视频中禁用右键(禁止用户下载)contextmenu(e){
  2. e.returnValue = false;
  3. },

7、设置倍速播放

this.$refs.videoPlayer.playbackRate = rate; // rate 一般在[2.0,1.75,1.5,1.0,0.75,0.5]范围

标签: 音视频 vue.js 前端

本文转载自: https://blog.csdn.net/m0_48571414/article/details/129128523
版权归原作者 贝小米在前端 所有, 如有侵权,请联系我们删除。

“video 自定义视频播放控件”的评论:

还没有评论