如何使用 TailwindCSS 和 JavaScript 构建自定义 HTML5 视频播放器

HTML5 内置了原生视频播放器。它拥有简单的用户界面、功能以及一些浏览器中的基本控件。虽然浏览器默认的视频播放器功能运行完美,但其用户界面不够美观,整体上缺乏美感。

因此,大多数现代网络应用程序和平台都不会向用户提供默认的内置 HTML5 视频播放器。相反,他们会构建自己的定制版本,并配备流畅的用户界面,以使其平台更具吸引力和用户友好性。

如果您曾经好奇这些公司和网络平台如何实现这样的壮举,那么本文适合您。

您将获得一些实践经验,并按照分步指南学习如何构建和自定义您自己的 HTML5 视频播放器。您将学习如何自定义用户界面、扩展功能以及构建您自己的精彩自定义控件和功能。

您还将学习如何仅使用浏览器中 JavaScript 提供的本机视频 API 来构建所有这些内容 – 无需任何外部库或工具。

先决条件

  • HTML5 和 CSS 的基础知识
  • Tailwind CSS 基础知识
  • JavaScript(ES6)基础知识
  • 您选择的代码编辑器
  • 支持 JavaScript 现代功能的浏览器(例如 Chrome 或 Mozilla Firefox)

入门

在本文中,我们将使用 Tailwind CSS 作为样式工具来构建自定义视频播放器 UI。我们还将使用 JavaScript 来构建控件的功能。

请注意,使用 Tailwind CSS 是可选的,因为任何样式工具都可以在这里使用,例如 SCSS、CSS、styled-components 等 – 这完全取决于您。

我将本教程分为几个部分,每个部分分别介绍自定义视频播放器功能的一个特定方面。每个新部分都将在前几个部分的基础上逐步完善播放器。读完本文后,您将拥有一个功能齐全的 HTML5 自定义视频播放器。

在本教程中,我们将重点介绍视频播放器的特定功能。这些功能将为构建其他功能提供机会和思路。我们将介绍的功能包括:

  • 播放和暂停
  • 倒回和快进
  • 静音和取消静音
  • 视频搜索
  • 键盘导航(利用空格键播放和暂停,利用箭头键快退和快进)。

我们不会在这里讨论响应式设计,因为我们不会专注于让视频播放器响应移动设备。这应该会给你带来挑战和学习机会。

现在,让我们深入研究设置我们的开发环境,以便我们可以开始构建。

如何设置开发环境

第一步是搭建一个高效的开发环境,以确保工作流程的顺畅。我们将使用Vite来实现这一点。

在进入本节的下一部分之前,请确保您的计算机上安装了NodeJSNPMYarn,因为它们对于安装工具和无缝设置开发环境是必需的。

如何使用 Vite 设置项目

要在 Vite 中搭建项目,请打开终端并输入以下命令:

yarn create vite

Vite 将指导您配置和选择适合您的开发环境的工具。

第一步是选择项目名称——您可以自由选择任何您喜欢的名称。在本文中,我将使用“html5-video-player”作为项目名称。

运行“yarn create vite”命令后的终端输出

下一步是选择项目框架。本项目将使用纯 JavaScript 编写,因此请选择“Vanilla”,然后在下一个提示中选择“JavaScript”。

输入项目名称后终端输出,要求选择项目框架


选择“Vanilla”框架后的终端输出

现在,Vite 已使用所选工具成功设置了您的环境。现在是时候安装 Vite 正常运行所需的依赖项了。请按照 Vite 在 CLI 中提供的说明进行操作。

终端显示环境设置成功消息

如果您的项目名称与我的类似,请直接按原样运行以下命令。如果您选择了其他名称,只需将我的项目名称替换为您的项目名称,然后按相同方式操作即可。

cd html5-video-player

此命令将导航到你的开发环境所在的项目目录。从那里,你可以继续安装依赖项。

yarn

安装依赖项后,我们继续下一步,设置 Tailwind CSS 作为我们的样式工具。这个过程很简单,类似于我们设置 Vite 的方式。

打开终端并执行以下命令:

yarn add -D tailwindcss postcss autoprefixer

这将安装我们的样式工具 Tailwind CSS,以及 PostCSS 和 Autoprefixer。这些工具将帮助 Tailwind CSS 在您的项目中有效运行。

下一个命令涉及设置 Tailwind CSS 和 PostCSS 的配置文件。

再次打开本地终端并输入以下命令:

npx tailwindcss init

创建 Tailwind CSS 配置文件。

如命令消息中所述,tailwind.config.js将在项目文件夹的根目录下生成一个名为 的文件。此文件将包含您的样式配置,包括字体、颜色、插件等设置。有关更多详细信息,请参阅TailwindCSS 文档

打开代码编辑器中生成的 Tailwind CSS 配置文件,并对其进行以下编辑:

/** @type {import('tailwindcss').Config} */
export default {
  content: ['./index.html'],
  theme: {
    extend: {},
  },
  plugins: [],
}

在这里,我们简单地编辑了content键值,以指定 TailwindCSS 读取 Tailwind CSS 类的文件。这个文件恰好是index.html我们主要工作所在的文件。

接下来,您需要配置 PostCSS,它不像 TailwindCSS 那样提供自动设置命令。因此,您需要手动创建配置文件。导航到项目的根文件夹并创建一个名为 的文件postcss.config.js。

创建postcss.config.js文件后,只需将提供的代码片段复制并粘贴到文件中。

export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

接下来,配置你的style.css文件以使用 Tailwind CSS 默认值。这样可以省去你手动设置 CSS 默认值的繁琐工作。

在代码编辑器中打开该style.css文件,删除其内容,然后将以下代码片段粘贴到文件中:

@tailwind base;
@tailwind components;
@tailwind utilities;

删除不必要的文件和代码

Vite 生成的文件主要用作添加自定义文件和高效使用打包工具的指南。因此,您可以删除其中的大部分文件,因为它们对于本项目来说并非必需。

以下是要从项目中删除的文件:

  1. counter.js
  2. javascript.svg

完成后,您可以继续本节的下一步,即删除不必要的代码。

打开main.js位于项目根目录的文件,并删除其中的所有代码。

然后,导航到该index.html文件并删除其所有当前内容。之后,将以下代码片段复制并粘贴到文件中:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="./style.css" />
    <title>HTML5 Custom Video Player</title>
  </head>
  <body>
    <h1 class="text-3xl font-bold underline text-red-800">Hello world!</h1>
    <script type="module" src="/main.js"></script>
  </body>
</html>

至此,您已完成本部分!您的开发环境现已设置完毕,您可以开始构建自定义 HTML5 视频播放器了。

要确认您的环境设置正确,请检查以下内容:

  1. 项目文件和文件夹应类似于以下结构:

项目设置完成:Visual Studio Code 显示项目结构。

  1. 打开终端并运行以下命令:
yarn dev

这将创建一个开发服务器,用于托管您的网页。打开 Vite 提供的 URL。

 

使用“yarn dev”命令启动 Vite 开发服务器。

打开链接后http://localhost:5173/,您应该会看到以下内容:

执行“yarn dev”命令后显示的初始用户界面。

恭喜!您已成功完成开发环境的设置,这将使我们能够高效地构建自定义 HTML5 视频播放器。

故障排除:如果您发现设置未按预期运行,请不要担心。只需删除项目文件夹并重复此过程即可。您可能错过了某个步骤,或者某些工具可能未正确安装。此外,请仔细检查您的 Tailwind CSS 和 PostCSS 配置文件,以确保它们包含如上所示的正确代码。

如何使用 Tailwind CSS 构建自定义 UI

本节涵盖构建自定义 HTML5 视频播放器 UI 所需的所有样式。我们将逐步讲解整个流程。

首先,将以下链接标签复制并粘贴到 HTML 的头部,位于样式表链接的上方:

<link
  href="https://fonts.googleapis.com/icon?family=Material+Icons"
  rel="stylesheet"
/>

这使我们能够使用Materialize CSS 图标,这对于在 UI 中设置按钮样式至关重要。

接下来,我们重点介绍如何在标记中设置视频元素的样式。只需body使用下面提供的代码片段替换该元素即可:

<body class="bg-indigo-950 p-10">
  <div
    id="container"
    class="w-4/5 h-4/5 mx-auto rounded-lg overflow-hidden relative group"
  >
    <!-- VIDEO -->
    <figure>
      <video class="w-full">
        <source src="/your-video.mp4" />
      </video>
    </figure>
  </div>
  <script type="module" src="/main.js"></script>
</body>

提供的代码片段包含视频元素的标记和样式,以及一个用作整个视频播放器 UI 容器的外部 div。视频元素嵌套在 figure 元素中。

对于source元素,请指定要播放的视频的路径。您可以在线查找视频,下载后将其添加到项目文件夹中的“public”目录。然后,将元素src的属性链接到视频文件。您可以在此处source找到免费的可下载视频。

接下来,让我们使用您在 HTML 中链接的Materialize CSS Icons来设置控件的样式。将以下代码片段放置在figurebody 元素内的元素下方。

<!-- CONTROLS -->
<div
  id="controls"
  class="opacity-0 p-5 absolute bottom-0 left-0 w-full transition-opacity duration-300 ease-linear group-hover:opacity-100"
>
  <!-- PROGRESS BAR -->
  <div id="progress-bar" class="h-1 w-full bg-white cursor-pointer mb-4">
    <div
      id="progress-indicator"
      class="h-full w-9 bg-indigo-800 transition-all duration-500 ease-in-out"
    ></div>
  </div>
  <div class="flex items-center justify-between">
    <div class="flex items-center justify-between">
      <!-- REWIND BUTTON -->
      <button
        id="rewind"
        class="transition-all duration-100 ease-linear hover:scale-125"
      >
        <i class="material-icons text-white text-3xl w-12">replay_10 </i>
      </button>

      <!-- PLAY BUTTON -->
      <button
        id="play-pause"
        class="transition-all duration-100 ease-linear hover:scale-125"
      >
        <i class="material-icons text-white text-5xl inline-block w-12"
          >play_arrow</i
        >
      </button>

      <!-- FAST FORWARD BUTTON -->
      <button
        id="fast-forward"
        class="transition-all duration-100 ease-linear hover:scale-125"
      >
        <i class="material-icons text-white text-3xl w-12">forward_10 </i>
      </button>
    </div>

    <div>
      <!-- VOLUME BUTTON -->
      <button
        id="volume"
        class="transition-all duration-100 ease-linear hover:scale-125"
      >
        <i class="material-icons text-white text-3xl">volume_up</i>
      </button>
    </div>
  </div>
</div>

此代码段定义了视频播放器控件的布局和行为。首先,设置一个容器 div ( <div id="controls">) 来容纳所有控件元素。该容器最初是不可见的 ( ),当用户将鼠标悬停在其上方 ( ) 时opacity-0,它会通过平滑的过渡效果 ( ) 变为可见。transition-opacity duration-300 ease-lineargroup-hover:opacity-100

容器内有一个进度条 ( <div id="progress-bar">),用于跟踪视频的播放进度。它由一个白色背景条 ( ) 和一个可移动的靛蓝色bg-white指示器( ) 组成。进度条具有响应功能,允许用户跳转到视频的不同部分。<div id="progress-indicator">bg-indigo-800

进度条下方是各种功能的控制按钮。倒回、播放/暂停和快进按钮被分组在一个弹性容器 ( <div class="flex items-center justify-between">) 内。每个按钮 ( <button>) 的样式设置为hover:scale-125在鼠标悬停时略微放大 ( )。

  • 倒退按钮 ( <button id="rewind">) 包含一个图标 ( <i class="material-icons text-white text-3xl w-12">replay_10</i>),表示倒退十秒。
  • 播放/暂停按钮 ( ) 包含一个在播放和暂停状态之间切换的<button id="play-pause">图标 ( )。<i class="material-icons text-white text-5xl w-12">play_arrow</i>
  • 快进按钮 ( <button id="fast-forward">) 包含一个图标 ( <i class="material-icons text-white text-3xl w-12">forward_10</i>),表示快进十秒。

<button id="volume">另外,控制按钮右侧还有一个音量按钮 ( )。它包含一个音量图标 ( <i class="material-icons text-white text-3xl w-12">volume_up</i>)。

总的来说,这段代码结合了 HTML 和 Tailwind CSS 类,为视频播放器创建了一组功能齐全、外观吸引人的控件。

最后的难题是禁用默认浏览器功能,我们不希望我们的自定义 HTML5 视频播放器与浏览器提供的默认样式发生冲突或被其覆盖。

将下面的代码片段复制并粘贴到您的style.css文件中,位于 Tailwind CSS 指令的正下方:

@layer base {
  video::-webkit-media-controls {
    display: none;
  }

  video::-webkit-media-controls-play-button {
    display: none;
  }

  video::-webkit-media-controls-volume-slider {
    display: none;
  }

  video::-webkit-media-controls-mute-button {
    display: none;
  }

  video::-webkit-media-controls-timeline {
    display: none;
  }

  video::-webkit-media-controls-current-time-display {
    display: none;
  }
}

这段代码用于自定义 WebKit 浏览器引擎(常用于 Safari 和某些版本的 Google Chrome 等浏览器)为该<video>元素提供的默认媒体控件的外观和行为。

块中的每条 CSS 规则@layer base都针对默认媒体控件的特定部分,并通过将其display属性设置为 来隐藏它们none。以下是每条规则的详细说明:

  1. video::-webkit-media-controls:此规则针对元素的所有媒体控件<video>,并将其完全隐藏。通过隐藏这些控件,您可以使用 JavaScript 和 CSS 实现自定义控件,从而在不同浏览器中提供更加个性化且一致的用户体验。
  2. video::-webkit-media-controls-play-button:此规则针对默认媒体控件中的播放按钮并将其隐藏。如果我们使用自定义播放按钮设计或以编程方式处理播放控制,则可能需要隐藏播放按钮。
  3. video::-webkit-media-controls-volume-slider:此规则以默认媒体控件中的音量滑块为目标,并将其隐藏。与隐藏播放按钮类似,如果您要实现自己的音量控制界面,也可以选择隐藏音量滑块。
  4. video::-webkit-media-controls-mute-button:此规则以默认媒体控件中的静音按钮为目标,并将其隐藏。如果您有自定义的静音/取消静音按钮,或者想要通过编程管理音频静音,则可以隐藏默认静音按钮。
  5. video::-webkit-media-controls-timeline:此规则以默认媒体控件中的时间线(进度条)为目标,并将其隐藏。通过隐藏时间线,您可以实现自定义样式和其他功能的进度条。
  6. video::-webkit-media-controls-current-time-display:此规则以默认媒体控件中的当前时间显示为目标,并将其隐藏。如果您要实现用于显示当前播放时间的自定义界面,则可以隐藏默认显示。

总的来说,此代码允许完全自定义 WebKit 浏览器提供的默认媒体控件,让您为网站上的视频播放创建独特且量身定制的用户体验。

检查您的本地主机 URL 以查看显示的自定义 UI,如下所示:

自定义视频播放器 UI,无需鼠标悬停,控件隐藏。

然而,悬停时,控件将淡入,UI 将显示如下:

自定义视频播放器 UI,鼠标悬停时可看到控件。

就这样!您已经成功构建了一个自定义的 HTML5 视频播放器。现在,是时候使用 JavaScript 来开发控件和功能,让它焕发生机了。我们将在接下来的章节中逐步讲解。

如何实现播放和暂停功能

要在 HTML5 自定义视频播放器上实现播放和暂停功能,首先需要使用标记中相应的 ID 选择播放和暂停按钮。您也可以选择视频元素。然后,您将使用浏览器中 JavaScript 提供的视频 API 以编程方式控制播放。现在就开始吧。

"use strict";

const playNpauseBtn = document.querySelector("#play-pause");
const video = document.querySelector("video");

从上面的代码片段来看:

  • "use strict";确保 JavaScript 在严格模式下运行,捕获常见的编码错误。
  • const playNpauseBtn = document.querySelector("#play-pause");使用其 ID 从 HTML 中选择播放/暂停按钮。
  • const video = document.querySelector("video");从 HTML 中选择视频元素。

接下来,让我们创建两个函数:

  1. playNpauseFn:此功能将处理视频的播放和暂停。
  2. updatePlayNPauseIcon:此功能将根据视频的当前状态更新播放和暂停图标。例如,如果视频正在播放,则会显示暂停图标,反之亦然。

现在,让我们检查一下它在下面的代码片段中如何发挥作用。

function playNpauseFn() {
  video.paused ? video.play() : video.pause();
}

function updatePlayNPauseIcon() {
  const icon = playNpauseBtn.querySelector("i");
  icon.textContent = "";

  icon.textContent = video.paused ? "play_arrow" : "paused";
}

让我们了解一下发生了什么。首先从playNpauseFn函数开始,当它被调用时,它会使用 Video API 中提供的方法检查视频的当前状态paused。如果视频已暂停,则播放视频。否则,暂停视频。这是使用 JavaScript 中的三元运算符实现的。

或者,您可以使用 if/else 语句重写此语句,如下所示:

function playNpauseFn() {
  if (video.paused) {
    video.play();
  } else {
    video.paused();
  }
}

上面的代码示例完成与以前版本相同的任务 – 任何一个都可以工作。

现在,我们来看看第二个函数。updatePlayNPauseIcon该函数根据视频的当前状态更新播放和暂停图标。我们来回顾一下它的实现方式。

查看下面的图标样式:

<button
  id="play-pause"
  class="transition-all duration-100 ease-linear hover:scale-125"
>
  <i class="material-icons text-white text-5xl inline-block w-12">play_arrow</i>
</button>

这段代码创建了一个 ID 为“play-pause”的按钮,该按钮包含一个由<i>标签指定的图标。Materialize CSS 使用标签内的文本“play_arrow”<i>来显示匹配的图标。如果您更改标签内的文本<i>,Materialize CSS 也会相应地更新图标。

现在,我们来关注负责更新图标的函数。下面单独看一下:

function updatePlayNPauseIcon() {
  const icon = playNpauseBtn.querySelector("i");
  icon.textContent = "";

  icon.textContent = video.paused ? "play_arrow" : "paused";
}

此函数updatePlayNPauseIcon()负责根据视频的当前状态更新播放/暂停图标。

  1. 它首先选择播放/暂停按钮内的图标元素。
  2. 然后,它会清除图标内所有现有的文本内容。
  3. 最后,如果视频暂停,则将图标的文本内容设置为“play_arrow”;如果视频正在播放,则设置为“paused”。这会动态更改按钮上显示的图标,以反映当前的播放状态。

注意:以编程方式更新图标的方式可能因图标服务及其 API 而异。此特定实现特定于 Materialize CSS 图标。

接下来,让我们将这些函数连接到触发它们的事件。让我们看看它是如何工作的:

video.addEventListener("play", updatePlayNPauseIcon);
video.addEventListener('click', playNpauseFn)
video.addEventListener("pause", updatePlayNPauseIcon);
playNpauseBtn.addEventListener("click", playNpauseFn);

在此代码中:

  • video.addEventListener("play", updatePlayNPauseIcon);:此行向视频元素添加了一个事件监听器,专门监听“play”事件。当视频开始播放时,它会触发该updatePlayNPauseIcon函数,并相应地更新播放/暂停图标。
  • video.addEventListener('click', playNpauseFn):此行向视频元素添加了一个事件监听器,用于监听“click”事件。当视频被点击时,会触发playNpauseFn相应的函数,播放或暂停视频。
  • video.addEventListener("pause", updatePlayNPauseIcon);:此行向视频元素添加一个事件监听器,用于监听“暂停”事件。当视频暂停时,它会触发该updatePlayNPauseIcon函数来更新播放/暂停图标。
  • playNpauseBtn.addEventListener("click", playNpauseFn);:此行向播放/暂停按钮元素添加一个事件监听器。当点击按钮时,会触发playNpauseFn播放或暂停视频的函数。

我们在两个选定元素上设置了四个事件监听器。让我们来分解一下具体发生了什么:

  • 视频元素监听“play”事件。当视频开始播放时,它会触发updatePlayNPauseIcon,并根据视频的当前状态更新图标。
  • 视频元素还会监听点击事件。点击后会触发playNpauseFn,从而在播放和暂停视频之间切换。
  • 此外,视频元素会监听“暂停”事件。当视频暂停时,它会触发playNpauseFn,切换视频的播放状态。
  • 播放/暂停按钮元素也会监听点击事件。点击后,它会触发playNpauseFn,在播放和暂停视频之间切换。

本节到此结束。现在您可以尝试播放和暂停功能了。视频应该可以正常暂停和播放,图标也会正确更新。

目前您的自定义视频播放器应该执行以下操作:

测试播放和暂停功能

在下一节中,我们将实现倒带和快进功能。

如何实现快退和快进功能

现在我们已经实现了播放和暂停功能,接下来要添加的功能是快退和快进。这些常用功能允许用户在视频中按设定的秒数快进或快退。

首先,让我们使用 ID 从 HTML 文档中选择相应的按钮并将它们存储在变量中:

const rewindBtn = document.querySelector("#rewind");
const fastForwardBtn = document.querySelector("#fast-forward");

完成后,您需要构建负责实现快退和快进功能的函数。以下是代码片段:

function rewindNforwardFn(type) {
  video.currentTime += type === "rewind" ? -10 : 10;
}

这个函数名为rewindNforward,负责快退或快进视频。它的工作原理如下:

  • 它需要一个名为的参数type,该参数指示您是要倒退还是快进。
  • 如果type是“倒带”,则会从视频的当前播放时间中减去 10 秒(video.currentTime)。
  • 如果type不是“倒带”(表示要快进),则会在视频的当前播放时间上增加 10 秒。这允许用户以 10 秒为间隔向后或向前浏览视频,具体取决于 的值type

接下来,您需要连接按钮上的事件监听器来触发该rewindNforward功能。

rewindBtn.addEventListener("click", () => rewindNforwardFn("rewind"));
fastForwardBtn.addEventListener("click", () => rewindNforwardFn("forward"));

此代码为快退和快进按钮添加了事件监听器。当点击快退按钮时,它会触发rewindNforward带有参数“rewind”的函数,表示您想要快退视频。

类似地,当单击快进按钮时,它会触发rewindNforward带有参数“forward”的函数,表示您想要快进视频。

请随意测试并观察它在用户界面(UI)上的运行情况。

测试快退和快进功能

如何实现静音和取消静音功能

要添加静音和取消静音功能,您需要遵循与之前功能相同的流程。

首先使用下列querySelector方法从 HTML 文档中选择音量按钮:

const volumeBtn = document.querySelector("#volume");

然后,创建负责静音和取消静音视频的功能,并在发生任一事件时相应地更新图标。

function muteNunmuteFn() {
  video.muted = video.muted ? false : true;
}

function updateVolumeIcon() {
  const icon = volumeBtn.querySelector("i");
  icon.textContent = "";
  icon.textContent = video.muted ? "volume_off" : "volume_up";
}

该代码包含两个函数:

  1. muteNunmuteFn():此功能切换视频的静音状态。如果视频当前处于静音状态,则取消静音。否则,将视频静音。
  2. updateVolumeIcon():此函数用于更新音量按钮上显示的音量图标。它会清除所有现有的图标内容,然后如果视频已静音,则将图标文本设置为“volume_off”,如果视频未静音,则将图标文本设置为“volume_up”。

最后一步是将函数与事件监听器连接起来,以便在事件触发时执行它们。以下是相关代码片段:

video.addEventListener("volumechange", updateVolumeIcon);
volumeBtn.addEventListener("click", muteNunmuteFn);

这段代码设置了两件事:

  1. 它为视频元素添加了一个事件监听器,用于监听“volumechange”事件。当该事件发生时(即音量发生变化时),会触发该updateVolumeIcon函数来更新音量图标。
  2. 它为音量按钮添加了一个事件监听器。当点击音量按钮时,它会触发该muteNunmuteFn函数,在视频静音和取消静音之间切换。

play与和事件类似pause,视频也会volumechange在音量或静音状态发生变化时触发一个事件。您可以设置视频监听此事件,因此当该事件发生时,事件监听器会运行相应的函数来更新音量图标。

测试静音和取消静音功能

如何根据视频时间更新进度条

在本节中,您将了解如何在视频播放时更新进度条,以便用户跟踪他们在视频中的进度。

目前,进度条不会随着视频播放和时间变化而移动。我们将修复这个问题

首先,您需要移除进度条的固定宽度样式。它最初是为了样式设置而添加的,但现在不再需要,因为您将使用 JavaScript 动态调整宽度。将 div 元素中的类名从 更新为 ,w-9w-0使用 id 为“progress-indicator”。

<!-- PROGRESS BAR -->
<div id="progress-bar" class="h-1 w-full bg-white cursor-pointer mb-4">
  <div
    id="progress-indicator"
    class="h-full w-0 bg-indigo-800 transition-all duration-500 ease-in-out"
  ></div>
</div>

接下来实现进度条的更新,第一步是选中进度条指示器元素。该元素的宽度会随着视频时间的推移而增加。以下是实现该功能的代码片段:

const progressIndicator = document.querySelector("#progress-indicator");

一旦选择了进度指示器,您的下一个任务就是实现负责更新它的功能。

function updateProgress() {
  const progressPercentage = (video.currentTime / video.duration) * 100;

  progressIndicator.style.width = `${progressPercentage}%`;
}

在上面的代码片段中,调用的函数updateProgress通过将视频的当前时间除以其总时长,然后乘以 100 来计算视频进度的百分比。此百分比用于设置进度指示器元素的宽度,直观地表示已观看了多少视频。

让我们分解一下这个函数。第一行代码计算视频当前时长占总时长的百分比。计算方法是将当前时间除以视频总时长。例如,如果视频时长为 30 秒,当前时间为 3 秒,则 3 除以 30 等于 0.1。

然后把这个小数乘以 100 得到百分比。所以,0.1 乘以 100 等于 10。这意味着你已经完成了 30 秒视频的 10%。

最后,您使用这个百分比来相应地更新进度指示器的宽度。

接下来,我们添加一个触发该函数的事件监听器。请参阅下面的代码片段:

video.addEventListener('timeupdate', updateProgress);

与视频 API 中的其他事件类似,还有一个名为 的事件。此事件在视频的 发生变化timeupdate时触发。因此,随着时间的更新,每次触发该事件时都会自动执行该函数,从而使进度指示器相应更新。currentTimeupdateProgress

测试时间进度功能

如何实现搜索功能

搜索功能是视频播放器至关重要的方面。虽然快退和快进对于短时间的跳跃很有效,但用户通常希望更大幅度地跳转到视频的特定部分。点击快退或快进只会以固定的增量移动,这可能会让用户感到沮丧。因此,搜索功能在这种情况下显得尤为重要。

让我们首先从文档对象模型 (DOM) 中选择进度条元素。

const progessBar = document.querySelector("#progress-bar");

使用 ID 从 DOM 获取进度条后,下一步就是构造查找函数。具体实现如下代码片段:

function seekingFn(e) {
  const updatedTime = (e.offsetX / progessBar.offsetWidth) * video.duration;

  video.currentTime = updatedTime;
}

让我们分解该函数并了解发生了什么。

该函数seekingFn根据用户在进度条上点击的位置调整视频的当前播放时间。它通过将点击位置相对于进度条宽度的水平偏移量除以进度条的总宽度来计算更新时间。然后,将其乘以视频的总时长。最后,将计算出的更新时间设置为视频的当前时间。

接下来,添加事件监听器:

let mouseIsDown = false;

progessBar.addEventListener("mousedown", () => (mouseIsDown = true));
progessBar.addEventListener("mouseup", () => (mouseIsDown = false));
progessBar.addEventListener("click", seekingFn);
progessBar.addEventListener("mousemove", (e) => mouseIsDown && seekingFn);

在上面的代码片段中,代码处理进度条上的鼠标事件以实现寻求功能:

  • mouseIsDown是一个跟踪鼠标按钮是否被按下的变量。
  • 当鼠标按钮被按下时(mousedown事件),mouseIsDown设置为 true。
  • 当鼠标按钮被释放(mouseup事件)时,mouseIsDown设置为 false。
  • 当点击进度条(click事件)时,seekingFn触发该函数以定位到点击的位置。
  • 当鼠标移动到进度条上(mousemove事件)时,如果mouseIsDown为真,即按下鼠标按钮,则seekingFn触发该函数,允许在拖动鼠标时进行搜索。

测试搜索功能

如何添加键盘导航以实现无障碍功能

我们的视频播放器目前支持鼠标和光笔等指针设备。但我们的目标是确保那些可能没有或无法使用这些设备的用户也能轻松使用。因此,我们致力于让定制的 HTML5 视频播放器无需指针设备即可使用,而是使用键盘。

使用空格键播放和暂停

我们先来改进一下播放和暂停功能。在大多数视频播放器中,我们通常使用键盘上的空格键来切换视频的播放和暂停。这是我们要实现的第一个键盘导航功能。

下面是一段代码片段,演示了如何实现这一点:

window.addEventListener("keyup", (e) => {
  if (e.code === "Space") {
    playNpauseFn();
  }
});

这段代码监听键盘上某个按键的释放,也就是“keyup”事件。如果释放的键恰好是空格键,则会触发切换视频播放和暂停的函数。你只需要重复使用之前编写的函数即可。

以下是代码的逐步解释:

  1. window.addEventListener("keyup", (e) => { ... })
  2. 您正在向对象添加事件监听器window
  3. 当释放某个键(keyup事件)时,会触发此监听器。
  4. (e) => { ... }
  5. 这是一个在事件发生时执行的箭头函数keyup
  6. e参数表示包含有关事件的信息的事件对象。
  7. if (e.code === "Space") { ... }
  8. 此条件检查释放的键是否是空格键。
  9. e.code提供触发事件的键的代码。
  10. playNpauseFn();
  11. 如果释放的键是空格键,则调用此函数。
  12. playNpauseFn功能负责在播放和暂停视频之间切换。

使用箭头键快退和快进

除了使用空格键播放和暂停之外,您还可以使用左箭头键倒退视频,使用右箭头键快进视频。

在前面播放和暂停功能的代码片段的基础上,您可以合并箭头键来实现视频的后退和快进。

window.addEventListener("keyup", (e) => {
  if (e.code === "Space") {
    playNpauseFn();
  } else if (e.code === "ArrowLeft") {
    rewindNforwardFn("rewind");
  } else if (e.code === "ArrowRight") {
    rewindNforwardFn("forward");
  } else {
    return;
  }
});

这段代码在 window 对象上为 keyup 事件设置了一个事件监听器。当任意键被释放时,都会触发传入的回调函数,回调函数会以事件为参数。回调函数内部包含条件语句,用于判断按下的是哪个键:

  • 如果按下的键是空格键(“Space”),playNpauseFn则执行该功能,在视频的播放和暂停之间切换。
  • 如果按下的键是左箭头键(“ArrowLeft”),rewindNforwardFn则使用参数“rewind”调用该函数,表示视频应该倒回。
  • 如果按下的键是右箭头键(“ArrowRight”),rewindNforwardFn则使用参数“forward”调用该函数,表示视频应快进。
  • 如果按下的键不是空格键、左箭头或右箭头,则函数将返回而不执行任何操作。

您的代码现在应该是什么样子

我们现在完成了自定义 HTML5 视频播放器的构建。恭喜你学习了本课程。

如果您遇到任何困难或遗漏了任何步骤,请不要担心。您可以在下面找到每个主要文件的代码片段:

索引.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />
    <link rel="stylesheet" href="./style.css" />
    <title>HTML5 Custom Video Player</title>
  </head>
  <body class="bg-indigo-950 p-10">
    <div
      id="container"
      class="w-4/5 h-4/5 mx-auto rounded-lg overflow-hidden relative group"
    >
      <!-- VIDEO -->
      <figure>
        <video class="w-full">
          <source src="/oceans.mp4" />
        </video>
      </figure>

      <!-- CONTROLS -->
      <div
        id="controls"
        class="opacity-0 p-5 absolute bottom-0 left-0 w-full transition-opacity duration-300 ease-linear group-hover:opacity-100"
      >
        <!-- PROGRESS BAR -->
        <div id="progress-bar" class="h-1 w-full bg-white cursor-pointer mb-4">
          <div
            id="progress-indicator"
            class="h-full w-0 bg-indigo-800 transition-all duration-500 ease-in-out"
          ></div>
        </div>
        <div class="flex items-center justify-between">
          <div class="flex items-center justify-between">
            <!-- REWIND BUTTON -->
            <button
              id="rewind"
              class="transition-all duration-100 ease-linear hover:scale-125"
            >
              <i class="material-icons text-white text-3xl w-12">replay_10 </i>
            </button>

            <!-- PLAY BUTTON -->
            <button
              id="play-pause"
              class="transition-all duration-100 ease-linear hover:scale-125"
            >
              <i class="material-icons text-white text-5xl inline-block w-12"
                >play_arrow</i
              >
            </button>

            <!-- FAST FORWARD BUTTON -->
            <button
              id="fast-forward"
              class="transition-all duration-100 ease-linear hover:scale-125"
            >
              <i class="material-icons text-white text-3xl w-12">forward_10 </i>
            </button>
          </div>

          <div>
            <!-- VOLUME BUTTON -->
            <button
              id="volume"
              class="transition-all duration-100 ease-linear hover:scale-125"
            >
              <i class="material-icons text-white text-3xl">volume_up</i>
            </button>
          </div>
        </div>
      </div>
    </div>
    <script type="module" src="/main.js"></script>
  </body>
</html>

样式.css

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  video::-webkit-media-controls {
    display: none;
  }

  video::-webkit-media-controls-play-button {
    display: none;
  }

  video::-webkit-media-controls-volume-slider {
    display: none;
  }

  video::-webkit-media-controls-mute-button {
    display: none;
  }

  video::-webkit-media-controls-timeline {
    display: none;
  }

  video::-webkit-media-controls-current-time-display {
    display: none;
  }
}

main.js

"use strict";

const playNpauseBtn = document.querySelector("#play-pause");
const video = document.querySelector("video");
const rewindBtn = document.querySelector("#rewind");
const fastForwardBtn = document.querySelector("#fast-forward");
const volumeBtn = document.querySelector("#volume");
const progressIndicator = document.querySelector("#progress-indicator");
const progessBar = document.querySelector("#progress-bar");

function playNpauseFn() {
  video.paused ? video.play() : video.pause();
}

function updatePlayNPauseIcon() {
  const icon = playNpauseBtn.querySelector("i");
  icon.textContent = "";

  icon.textContent = video.paused ? "play_arrow" : "paused";
}

function rewindNforwardFn(type) {
  video.currentTime += type === "rewind" ? -10 : 10;
}

function muteNunmuteFn() {
  video.muted = video.muted ? false : true;
}

function updateVolumeIcon() {
  const icon = volumeBtn.querySelector("i");
  icon.textContent = "";
  icon.textContent = video.muted ? "volume_off" : "volume_up";
}

function updateProgress() {
  const progressPercentage = (video.currentTime / video.duration) * 100;

  progressIndicator.style.width = `${progressPercentage}%`;
}

function seekingFn(e) {
  const updatedTime = (e.offsetX / progessBar.offsetWidth) * video.duration;

  video.currentTime = updatedTime;
}

// PLAY AND PAUSE FUNCTIONALITY
video.addEventListener("play", updatePlayNPauseIcon);
video.addEventListener("click", playNpauseFn);
video.addEventListener("pause", updatePlayNPauseIcon);
playNpauseBtn.addEventListener("click", playNpauseFn);

// REWIND AND FAST FORWARD
rewindBtn.addEventListener("click", () => rewindNforwardFn("rewind"));
fastForwardBtn.addEventListener("click", () => rewindNforwardFn("forward"));

// MUTE AND UNMUTE
video.addEventListener("volumechange", updateVolumeIcon);
volumeBtn.addEventListener("click", muteNunmuteFn);

// PROGRESS
video.addEventListener("timeupdate", updateProgress);

// SEEKING
let mouseIsDown = false;

progessBar.addEventListener("mousedown", () => (mouseIsDown = true));
progessBar.addEventListener("mouseup", () => (mouseIsDown = false));
progessBar.addEventListener("click", seekingFn);
progessBar.addEventListener("mousemove", (e) => mouseIsDown && seekingFn);

// KEYBOARD NAVIGATIONS
window.addEventListener("keyup", (e) => {
  if (e.code === "Space") {
    playNpauseFn();
  } else if (e.code === "ArrowLeft") {
    rewindNforwardFn("rewind");
  } else if (e.code === "ArrowRight") {
    rewindNforwardFn("forward");
  } else {
    return;
  }
});

或者,您也可以在我上传的附件找到所有代码。

您可以通过此处访问实时站点。

 

视频 API 提供了丰富的功能供您尝试,例如添加播放速率控制、音量调节,甚至字幕。您还可以通过动画和交互来增强项目,并确保其对移动设备的响应能力,甚至可以为移动设备启用横屏模式。

想要获得更多灵感和想法,欢迎点击此处查看我的项目版本。

结论

恭喜!您已阅读完本文,并获得了构建自定义 HTML5 视频播放器的宝贵实践经验。通过整合键盘导航并优化可访问性,您确保了流畅的用户体验。

感谢您的阅读,下次再见!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。