HTML5 的 video 标签,实现简易播放器

在这里插入图片描述


前置知识点:

HTML <video> 元素用于在HTML或者XHTML文档中嵌入媒体播放器,用于支持文档内的视频播放。

  • currentTime:读取CurentTime返回一个双精度浮点值,指示以秒为单位的媒体的当前播放位置。如果video尚未开始播放,则会在开始播放后返回偏移量。通过CurentTime将当前播放位置设置为给定时间,会在加载媒体时将媒体查找到该位置(从指定的位置开始播放)。

  • duration(只读):一个双精度浮点值,它指示媒体的持续时间(总长度),以秒为单位,在媒体的时间线上。

  • volume:音量

  • playbackrate:播放速度

  • play():播放视频

  • pause():暂停视频

更多知识点:===》 https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/video

在这里插入图片描述
实现思路:

  1. 实现播放暂停功能
// 获取 video 和 toggle
const player = document.querySelector('.player')
const video = player.querySelector('.viewer')
const toggle = player.querySelector('.toggle')

当 video 标签和 控制按钮被点击时,切换播放状态

video.addEventListener('click', togglePlay)
toggle.addEventListener('click', togglePlay)

判断 video 的状态,如果当前是暂停,则调用 video 的 play。

// 切换播放状态
function togglePlay() {
  const method = video.paused ? 'play' : 'pause'
  video[method]()
}
  1. 切换播放状态图标,对 video 进行播放状态的监听
video.addEventListener('play', updatedToggle)
video.addEventListener('pause', updatedToggle)
// 切换播放状态图标
function updatedToggle() {
  const icon = video.paused ? '►' : '❚ ❚'
  toggle.textContent = icon
}
  1. 实现前进后退功能

获取页面上的两个前进后退按钮,为其添加 click 事件。

const skipButtons = player.querySelectorAll('[data-skip]')

skipButtons.forEach(skipButton => skipButton.addEventListener('click', skip))

获取 skip 按钮上的自定义属性,改变 video 的 currentTime

function skip() {
  video.currentTime += parseFloat(this.dataset.skip)
}
  1. 改变播放速度和音量

获取页面上控制音量和播放速度的两个按钮,为其添加 change 事件和 mousemove 事件,实现点击或拖动改变的效果。

const ranges = player.querySelectorAll('.player__slider')

ranges.forEach(range => range.addEventListener('change', handleRangeUpdate))
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate))

// 改变播放速度和音量
function handleRangeUpdate() {
  video[this.name] = this.value
}
  1. 实现播放进度条的颜色移动
const progressBar = player.querySelector('.progress__filled')

监听 video 标签的 timeupdate

video.addEventListener('timeupdate', handleProgress)

用当前播放的时间 video.currentTime 除以视频的总时长 video.duration

// 改变进度条
function handleProgress() {
  const percent = (video.currentTime / video.duration) * 100;
  progressBar.style.flexBasis = `${percent}%`;
}
  1. 拖动进度条,视频切换到对应的播放时间
const progress = player.querySelector('.progress')

需要一个变量,控制切换是否生效

let mousedown = false

监听 progress 的 clickmousemovemousedownmouseup 四个事件

let mousedown = false
progress.addEventListener('click', scrub)
progress.addEventListener('mousemove', (e) => mousedown && scrub(e))
progress.addEventListener('mousedown', () => mousedown = true)
progress.addEventListener('mouseup', () => mousedown = false)
// 点击切换播放进度
function scrub(e) {
  const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration
  video.currentTime = scrubTime
}

完整代码:

HTML

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>HTML Video Player</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>

  <div class="player">
    <div class="top" id="barrageList">
      <video class="player__video viewer" src="652333414.mp4"></video>
    </div>

    <div class="player__controls">
      <div class="progress">
        <div class="progress__filled"></div>
      </div>
      <button class="player__button toggle" title="Toggle Play"></button>
      <input type="range" name="volume" class="player__slider" min="0" max="1" step="0.05" value="1">
      <input type="range" name="playbackRate" class="player__slider" min="0.5" max="2" step="0.1" value="1">
      <button data-skip="-10" class="player__button">« 10s</button>
      <button data-skip="25" class="player__button">25s »</button>
    </div>
  </div>
  <script src="./scripts-my.js"></script>
</body>

</html>

CSS

html {
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  margin: 0;
  padding: 0;
  display: flex;
  background: #7A419B;
  min-height: 100vh;
  background: linear-gradient(135deg, #7c1599 0%,#921099 48%,#7e4ae8 100%);
  background-size: cover;
  align-items: center;
  justify-content: center;
}

.player {
  max-width: 750px;
  border: 5px solid rgba(0,0,0,0.2);
  box-shadow: 0 0 20px rgba(0,0,0,0.2);
  position: relative;
  font-size: 0;
  overflow: hidden;
}

/* This css is only applied when fullscreen is active. */
.player:fullscreen {
  max-width: none;
  width: 100%;
}

.player:-webkit-full-screen {
  max-width: none;
  width: 100%;
}

.player__video {
  width: 100%;
}

.player__button {
  background: none;
  border: 0;
  line-height: 1;
  color: white;
  text-align: center;
  outline: 0;
  padding: 0;
  cursor: pointer;
  max-width: 50px;
}

.player__button:focus {
  border-color: #ffc600;
}

.player__slider {
  width: 10px;
  height: 30px;
}

.player__controls {
  display: flex;
  position: absolute;
  bottom: 0;
  width: 100%;
  transform: translateY(100%) translateY(-5px);
  transition: all .3s;
  flex-wrap: wrap;
  background: rgba(0,0,0,0.1);
}

.player:hover .player__controls {
  transform: translateY(0);
}

.player:hover .progress {
  height: 15px;
}

.player__controls > * {
  flex: 1;
}

.progress {
  flex: 10;
  position: relative;
  display: flex;
  flex-basis: 100%;
  height: 5px;
  transition: height 0.3s;
  background: rgba(0,0,0,0.5);
  cursor: ew-resize;
}

.progress__filled {
  width: 50%;
  background: #ffc600;
  flex: 0;
  flex-basis: 0%;
}

/* unholy css to style input type="range" */

input[type=range] {
  -webkit-appearance: none;
  background: transparent;
  width: 100%;
  margin: 0 5px;
}

input[type=range]:focus {
  outline: none;
}

input[type=range]::-webkit-slider-runnable-track {
  width: 100%;
  height: 8.4px;
  cursor: pointer;
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0);
  background: rgba(255,255,255,0.8);
  border-radius: 1.3px;
  border: 0.2px solid rgba(1, 1, 1, 0);
}

input[type=range]::-webkit-slider-thumb {
  height: 15px;
  width: 15px;
  border-radius: 50px;
  background: #ffc600;
  cursor: pointer;
  -webkit-appearance: none;
  margin-top: -3.5px;
  box-shadow:0 0 2px rgba(0,0,0,0.2);
}

input[type=range]:focus::-webkit-slider-runnable-track {
  background: #bada55;
}

input[type=range]::-moz-range-track {
  width: 100%;
  height: 8.4px;
  cursor: pointer;
  box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0);
  background: #ffffff;
  border-radius: 1.3px;
  border: 0.2px solid rgba(1, 1, 1, 0);
}

input[type=range]::-moz-range-thumb {
  box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0);
  height: 15px;
  width: 15px;
  border-radius: 50px;
  background: #ffc600;
  cursor: pointer;
}

.top video {
  width: 100%;
}

.bot {
  display: flex;
}

.bot .barrage-color {
  width: 80px;
}

.bot .barrage-input {
  width: 240px;
  margin-left: -15px;
}

.bot .barrage-input input {
  width: 100%;
  height: 25px;
  font-size: 16px;
}

#textColor {
  width: 50px;
  height: 25px;
  border: none;
}

.bot .barrage-btn {
  flex: 1;
  text-align: center;
  background: cyan;
  line-height: 25px;
  cursor: pointer;
  border-top-right-radius: 6px;
  border-bottom-right-radius: 6px;
}

.msg {
  transform: translateX(-100px);
  position: absolute;
  z-index: 999;
  font-weight: 800;
  animation: l-2-r 6s linear;
}

/* 从左到右的移动动画 */
@keyframes l-2-r {
  from {
    transform: translateX(500px);
  }
  to {
    transform: translateX(-100px);
  }
}

JavaScript

// 首先实现播放暂停功能
const player = document.querySelector('.player')
const video = player.querySelector('.viewer')
const toggle = player.querySelector('.toggle')
const skipButtons = player.querySelectorAll('[data-skip]')
const volumeInput = player.querySelector('input[name="volume"]')
const ranges = player.querySelectorAll('.player__slider')
const progress = player.querySelector('.progress')
const progressBar = player.querySelector('.progress__filled')
const barrageList = document.getElementById('barrageList')

video.addEventListener('click', togglePlay)
toggle.addEventListener('click', togglePlay)
video.addEventListener('play', updatedToggle)
video.addEventListener('pause', updatedToggle)
video.addEventListener('timeupdate', handleProgress)
skipButtons.forEach(skipButton => skipButton.addEventListener('click', skip))
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate))
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate))

let mousedown = false
progress.addEventListener('click', scrub)
progress.addEventListener('mousemove', (e) => mousedown && scrub(e))
progress.addEventListener('mousedown', () => mousedown = true)
progress.addEventListener('mouseup', () => mousedown = false)

// 切换播放状态
function togglePlay() {
  const method = video.paused ? 'play' : 'pause'
  video[method]()
}

// 切换播放状态图标
function updatedToggle() {
  const icon = video.paused ? '►' : '❚ ❚'
  toggle.textContent = icon
}

// 前进后退功能
function skip() {
  video.currentTime += parseFloat(this.dataset.skip)
}

// 改变播放速度和音量
function handleRangeUpdate() {
  video[this.name] = this.value
}

// 改变进度条
function handleProgress() {
  const percent = (video.currentTime / video.duration) * 100;
  progressBar.style.flexBasis = `${percent}%`;
}

// 点击切换播放进度
function scrub(e) {
  const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration
  video.currentTime = scrubTime
}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值