自定义视频播放控件样式

    技术2022-07-11  114

    自定义视频播放控件样式

    In this guide, you will learn how to create a custom video player using the <video> element and CanJS. The custom video player will:

    在本指南中,您将学习如何使用<video>元素和CanJS创建自定义视频播放器。 自定义视频播放器将:

    Have custom play and pause buttons.

    具有自定义播放和暂停按钮。 Show the current time and duration of the video.

    显示视频的当前时间和时长。

    Have a <input type="range"> slider that can adjust the position of the video.

    有一个<input type="range">滑块可以调整视频的位置。

    The final player looks like:

    最终玩家看起来像:

    演示地址

    The following sections are broken down into the following parts:

    以下各节分为以下几部分:

    The problem — A description of what the section is trying to accomplish.

    问题 -对本节要完成的工作的描述。

    What you need to know — Browser or CanJS APIs that are useful for solving the problem.

    您需要知道的 -对解决问题有用的浏览器或CanJS API。

    The solution — The solution to the problem.

    解决方案 —解决问题的方法。

    建立 (Setup)

    START THIS TUTORIAL BY Forking THE FOLLOWING CodePen:

    通过分叉以下CodePen开始本教程 :

    Click the Edit in CodePen button. The CodePen will open in a new window. Click the Fork button.

    单击Edit in CodePen按钮。 CodePen将在新窗口中打开。 单击Fork按钮。

    演示地址

    This CodePen:

    该CodePen:

    Creates a <video> element that loads a video. Right click and select “Show controls” to see the video’s controls.

    创建一个<video>元素来加载视频。 右键单击并选择“显示控件”以查看视频的控件 。

    Loads CanJS's custom element library: Component.

    加载CanJS的自定义元素库: Component 。

    问题 (The problem)

    In this section, we will:

    在本节中,我们将:

    Create a custom <video-player> element that takes a src attribute and creates a <video> element within itself. We should be able to create the video like:

    创建一个具有src属性的自定义<video-player>元素,并在其内部创建一个<video>元素。 我们应该能够像这样创建视频:

    <video-player src:raw="http://bit.ly/can-tom-n-jerry"> </video-player>

    The embedded <video> element should have the native controls enabled.

    嵌入的<video>元素应启用本机控件。

    When complete, the result will look exactly the same as the player when you started. The only difference is that we will be using a custom <video-player> element in the HTML tab instead of the native <video> element.

    完成后,结果将与开始时的播放器完全相同。 唯一的区别是我们将在HTML选项卡中使用自定义的<video-player>元素,而不是本机的<video>元素。

    你需要知道的 (What you need to know)

    To set up a basic CanJS application (or widget), you define a custom element in JavaScript and use the custom element in your page’s HTML.

    要设置基本的CanJS应用程序(或小部件),请在JavaScript中定义一个自定义元素,然后在页面的HTML使用该自定义元素。

    To define a custom element, extend Component with a tag that matches the name of your custom element. For example:

    要定义自定义元素,请使用与您的自定义元素名称匹配的标签扩展Component 。 例如:

    Component.extend({ tag: "video-player" })

    Then you can use this tag in your HTML page:

    然后,您可以在HTML页面中使用此标记:

    <video-player></video-player>

    But this doesn’t do anything ... yet. Components add their own HTML through their view property:

    但这还没有做任何事情...。 组件通过其view属性添加自己HTML:

    Component.extend({ tag: "video-player", view: `<h2>I am a player!</h2>` });

    A component’s view is rendered with its ViewModel. For example, we can make a <video> display "http://bit.ly/can-tom-n-jerry" by defining a src property on the ViewModel and using it in the view like:

    组件的视图使用其ViewModel呈现。 例如,我们可以通过在ViewModel上定义src属性并在如下视图中使用它来使<video>显示"http://bit.ly/can-tom-n-jerry" :

    Component.extend({ tag: "video-player", view: ` <video> <source src="{{src}}"/> </video> `, ViewModel: { src: {type: "string", default: "http://bit.ly/can-tom-n-jerry"} } });

    But we want the <video-player> to take a src attribute value itself and use that for the <source>’s src. For example, if we wanted the video to play "http://dl3.webmfiles.org/big-buck-bunny_trailer.webm" instead of "http://bit.ly/can-tom-n-jerry", we would:

    但是我们希望<video-player>本身采用src属性值,并将其用于<source>的src 。 例如,如果我们希望视频播放"http://dl3.webmfiles.org/big-buck-bunny_trailer.webm"而不是"http://bit.ly/can-tom-n-jerry" ,我们将:

    Update <video-player> to pass "http://dl3.webmfiles.org/big-buck-bunny_trailer.webm" with toChild:raw:

    更新<video-player>以通过toChild:raw传递"http://dl3.webmfiles.org/big-buck-bunny_trailer.webm" :

    <video-player src:raw="http://dl3.webmfiles.org/big-buck-bunny_trailer.webm"/>

    Update the ViewModel to define a src property like:

    更新ViewModel以定义src属性,例如:

    Component.extend({ tag: "video-player", view: ` <video> <source src="{{src}}"/> {{!👀}} </video> `, ViewModel: { src: "string" } });

    Finally, to have a <video> element show the native controls, add a controls attribute like:

    最后,要使<video>元素显示本机控件,请添加如下controls属性:

    <video controls>

    解决方案 (The solution)

    Update the JS tab to:

    将JS标签更新为:

    import {Component} from "//unpkg.com/can@5/core.mjs"; Component.extend({ //👀 tag: "video-player", //👀 view: ` {{!👀}} <video controls> {{!👀}} <source src="{{src}}"/> {{!👀}} </video> {{!👀}} `, //👀 ViewModel: { //👀 src: "string", //👀 } //👀 }); //👀

    Update the HTML to:

    将HTML更新为:

    <video-player src:raw="http://bit.ly/can-tom-n-jerry"></video-player> <!--👀-->

    在播放和暂停视频时更改播放/暂停按钮 (Make play / pause button change as video is played and paused)

    问题 (The problem)

    When the video is played or paused using the native controls, we want to change the content of a <button> to say “Play” or “Pause”.

    使用本机控件播放或暂停视频时,我们希望将<button>的内容更改为“播放”或“暂停” 。

    When the video is played, the button should say “Pause”. When the video is paused, the button should say “Play”.

    播放视频时,按钮应显示“暂停” 。 视频暂停时,按钮应显示“播放” 。

    We want the button to be within a <div> after the video element like:

    我们希望按钮位于视频元素之后的<div>内,例如:

    </video> <div> <button>Play</button> </div>

    你需要知道的 (What you need to know)

    To change the HTML content of the page, use {{#if(expression)}} and {{else}} like:

    要更改页面HTML内容,请使用{{#if(expression)}}和{{else}},如下所示:

    <button>{{#if(playing)}} Pause {{else}} Play {{/if}}</button>

    The view responds to values in the ViewModel. To create a boolean value in the ViewModel do:

    该视图响应ViewModel中的值。 要在ViewModel中创建boolean值,请执行以下操作:

    ViewModel: { // ... playing: "boolean", }

    Methods can be used to change the ViewModel. The following might create methods that change the playing value:

    方法可用于更改ViewModel 。 以下可能会创建更改playing价值的方法:

    ViewModel: { // ... play() { this.playing = true; }, pause() { this.playing = false; }, }

    You can listen to events on the DOM with on:event. For example, the following might listen to a click on a <div> and call doSomething():

    您可以使用on:event监听DOM 上的事件 。 例如,以下内容可能会监听<div>的点击并调用doSomething() :

    <div on:click="doSomething()">

    <video> elements have a variety of useful events, including play and pause events that are emitted when the video is played or paused.

    <video>元素具有各种有用的事件 ,包括在播放或暂停视频时发出的播放和暂停事件。

    解决方案 (The solution)

    Update the JavaScript tab to:

    将JavaScript标签更新为:

    import {Component} from "//unpkg.com/can@5/core.mjs"; Component.extend({ tag: "video-player", view: ` <video controls on:play="play()" {{!👀}} on:pause="pause()"> {{!👀}} <source src="{{src}}"/> </video> <div> {{!👀}} <button> {{!👀}} {{#if(playing)}} Pause {{else}} Play {{/if}} {{!👀}} </button> {{!👀}} </div> {{!👀}} `, ViewModel: { src: "string", playing: "boolean", //👀 play() { //👀 this.playing = true; //👀 }, //👀 pause() { //👀 this.playing = false; //👀 }, //👀 } });

    使单击“播放/暂停”按钮播放或暂停视频 (Make clicking the play/pause button play or pause the video)

    问题 (The problem)

    When the play/pause <button> we created in the previous section is clicked, we want to either play or pause the video.

    单击上一节中创建的播放/暂停 <button> ,我们要播放或暂停视频。

    你需要知道的 (What you need to know)

    CanJS prefers to manage the state of your application in ViewModel. The <video> player has state, such as if the video is playing. When the play/pause button is clicked, we want to update the state of the ViewModel and have the ViewModel update the state of the video player as a side effect.

    CanJS倾向于在ViewModel中管理应用程序的状态。 <video>播放器具有状态,例如正在playing视频。 单击“ 播放/暂停”按钮时,我们要更新ViewModel的状态,并让ViewModel更新视频播放器的状态作为副作用。

    What this means is that instead of something like:

    这意味着它不是这样的:

    togglePlay() { if ( videoElement.paused ) { videoElement.play() } else { videoElement.pause() } }

    We update the state like:

    我们将状态更新为:

    togglePlay() { this.playing = !this.playing; }

    And listen to when playing changes and update the video element like:

    并在playing更改时收听并更新video元素,例如:

    viewModel.listenTo("playing", function(event, isPlaying) { if ( isPlaying ) { videoElement.play() } else { videoElement.pause() } })

    This means that you need to:

    这意味着您需要:

    Listen to when the <button> is clicked and call a ViewModel method that updates the playing state.

    收听单击<button>时的声音,并调用更新playing状态的ViewModel方法。

    Listen to when the playing state changes and update the state of the <video> element.

    收听playing状态更改时的playing并更新<video>元素的状态。

    You already know everything you need to know for step #1. (Have the button call a togglePlay method with on:click="togglePlay()" and make the togglePlay() method toggle the state of the playing property.)

    你已经知道你需要知道的步骤#1的一切。 (让按钮使用on:click="togglePlay()"调用togglePlay方法,并使togglePlay()方法切换playing属性的状态。)

    For step #2, you need to use the connectedCallback lifecycle hook. This hook gives you access to the component’s element and is a good place to do side-effects. Its use looks like this:

    对于步骤2 ,您需要使用connectedCallback生命周期挂钩。 该挂钩使您可以访问组件的元素,并且是处理副作用的好地方。 它的用法如下所示:

    ViewModel: { // ... connectedCallback(element) { // perform mischief } }

    connectedCallback gets called once the component’s element is in the page. You can use listenTo to listen to changes in the ViewModel’s properties and perform side-effects. The following listens to when playing changes:

    一旦组件的element在页面中,就会调用connectedCallback 。 您可以使用listenTo来侦听ViewModel的属性中的更改并执行副作用。 playing更改时,以下内容会监听:

    ViewModel: { // ... connectedCallback(element) { this.listenTo("playing", function(event, isPlaying) { }) } }

    Use querySelector to get the <video> element from the <video-player> like:

    使用querySelector从<video-player>获取<video>元素,例如:

    element.querySelector("video")

    <video> elements have a .play() and .pause() methods that can start and stop a video.

    <video>元素具有可以启动和停止视频的.play()和.pause()方法。

    解决方案 (The solution)

    Update the JavaScript tab to:

    将JavaScript标签更新为:

    import {Component} from "//unpkg.com/can@5/core.mjs"; Component.extend({ tag: "video-player", view: ` <video controls on:play="play()" on:pause="pause()"> <source src="{{src}}"/> </video> <div> <button on:click="togglePlay()"> {{!👀}} {{#if(playing)}} Pause {{else}} Play {{/if}} </button> </div> `, ViewModel: { src: "string", playing: "boolean", play() { this.playing = true; }, pause() { this.playing = false; }, togglePlay() { //👀 this.playing = !this.playing; //👀 }, //👀 connectedCallback(element) { //👀 this.listenTo("playing", function(event, isPlaying) { //👀 if (isPlaying) { //👀 element.querySelector("video").play(); //👀 } else { //👀 element.querySelector("video").pause(); //👀 } //👀 }); //👀 } //👀 } });

    显示当前时间和持续时间 (Show current time and duration)

    问题 (The problem)

    Show the current time and duration of the video element. The time and duration should be formatted like: mm:SS. They should be presented within two spans like:

    显示视频元素的当前时间和持续时间。 时间和持续时间的格式应为: mm:SS 。 它们应在两个范围内显示:

    </button> <span>1:22</span> <span>2:45</span>

    你需要知道的 (What you need to know)

    Methods can be used to format values in can-stache. For example, you can uppercase values like this:

    方法可用于格式化can-stache中的值。 例如,您可以像这样大写值:

    <span>{{upper(value)}}</span>

    With a method like:

    使用类似的方法:

    ViewModel: { // ... upper(value) { return value.toString().toUpperCase(); } }

    The following can be used to format time:

    以下内容可用于格式化时间:

    formatTime(time) { if (time === null || time === undefined) { return "--"; } const minutes = Math.floor(time / 60); let seconds = Math.floor(time - minutes * 60); if (seconds < 10) { seconds = "0" + seconds; } return minutes + ":" + seconds; }

    Time is given as a number. Use the following to create a number property on the ViewModel:

    时间以数字形式给出。 使用以下命令在ViewModel上创建一个number属性:

    ViewModel: { // ... duration: "number", currentTime: "number" }

    <video> elements emit a loadmetadata event when they know how long the video is. They also emit a timeupdate event when the video’s current play position changes.

    <video>元素在知道视频多长时间时会发出loadmetadata事件 。 当视频的当前播放位置更改时,它们还会发出timeupdate事件 。

    videoElement.duration reads the duration of a video.videoElement.duration读取视频的时长。 videoElement.currentTime reads the current play position of a video.videoElement.currentTime读取视频的当前播放位置。

    You can get the element in an stache on:event binding with scope.element like:

    您可以使用scope.element像下面这样on:event绑定中获取元素:

    <video on:timeupdate="updateTimes(scope.element)"/>

    解决方案 (The solution)

    Update the JavaScript tab to:

    将JavaScript标签更新为:

    import {Component} from "//unpkg.com/can@5/core.mjs"; Component.extend({ tag: "video-player", view: ` <video controls on:play="play()" on:pause="pause()" on:timeupdate="updateTimes(scope.element)" {{!👀}} on:loadedmetadata="updateTimes(scope.element)"> {{!👀}} <source src="{{src}}"/> </video> <div> <button on:click="togglePlay()"> {{#if(playing)}} Pause {{else}} Play {{/if}} </button> <span>{{formatTime(currentTime)}}</span> / {{!👀}} <span>{{formatTime(duration)}} </span> {{!👀}} </div> `, ViewModel: { src: "string", playing: "boolean", duration: "number", //👀 currentTime: "number", //👀 updateTimes(videoElement) { //👀 this.currentTime = videoElement.currentTime || 0; //👀 this.duration = videoElement.duration; //👀 }, //👀 formatTime(time) { //👀 if (time === null || time === undefined) { //👀 return "--"; //👀 } //👀 const minutes = Math.floor(time / 60); //👀 let seconds = Math.floor(time - minutes * 60); //👀 if (seconds < 10) { //👀 seconds = "0" + seconds; //👀 } //👀 return minutes + ":" + seconds; //👀 }, //👀 play() { this.playing = true; }, pause() { this.playing = false; }, togglePlay() { this.playing = !this.playing; }, connectedCallback(element) { this.listenTo("playing", function(event, isPlaying) { if (isPlaying) { element.querySelector("video").play(); } else { element.querySelector("video").pause(); } }); } } });

    使范围在当前时间显示位置滑块 (Make range show position slider at current time)

    问题 (The problem)

    Create a <input type="range"/> element that changes its position as the video playing position changes.

    创建一个<input type="range"/>元素,该元素随视频播放位置的变化而改变其位置。

    The <input type="range"/> element should be after the <button> and before the currentTime span like:

    <input type="range"/>元素应位于<button>和currentTime跨度之前,例如:

    </button> <input type="range"/> <span>{{formatTime(currentTime)}}</span> /

    你需要知道的 (What you need to know)

    The range input can have an initial value, max value, and step size specified like:

    范围输入可以指定一个初始值,最大值和步长,例如:

    <input type="range" value="0" max="1" step="any"/>

    The range will have values from 0 to 1. We will need to translate the currentTime to a number between 0 and 1. We can do this with a computed getter property like:

    范围的值从0到1。我们需要将currentTime转换为0到1之间的数字。我们可以使用计算得到的getter属性来完成此操作,例如:

    ViewModel: { // ... get percentComplete() { return this.currentTime / this.duration; }, }

    Use key:from to update a value from a ViewModel property like:

    使用key:from从ViewModel属性更新值,例如:

    <input value:from="percentComplete"/>

    解决方案 (The solution)

    Update the JavaScript tab to:

    将JavaScript标签更新为:

    import {Component} from "//unpkg.com/can@5/core.mjs"; Component.extend({ tag: "video-player", view: ` <video controls on:play="play()" on:pause="pause()" on:timeupdate="updateTimes(scope.element)" on:loadedmetadata="updateTimes(scope.element)"> <source src="{{src}}"/> </video> <div> <button on:click="togglePlay()"> {{#if(playing)}} Pause {{else}} Play {{/if}} </button> <input type="range" value="0" max="1" step="any" {{!👀}} value:from="percentComplete"/> {{!👀}} <span>{{formatTime(currentTime)}}</span> / <span>{{formatTime(duration)}} </span> </div> `, ViewModel: { src: "string", playing: "boolean", duration: "number", currentTime: "number", get percentComplete() { //👀 return this.currentTime / this.duration; //👀 }, //👀 updateTimes(videoElement) { this.currentTime = videoElement.currentTime || 0; this.duration = videoElement.duration; }, formatTime(time) { if (time === null || time === undefined) { return "--"; } const minutes = Math.floor(time / 60); let seconds = Math.floor(time - minutes * 60); if (seconds < 10) { seconds = "0" + seconds; } return minutes + ":" + seconds; }, play() { this.playing = true; }, pause() { this.playing = false; }, togglePlay() { this.playing = !this.playing; }, connectedCallback(element) { this.listenTo("playing", function(event, isPlaying) { if (isPlaying) { element.querySelector("video").play(); } else { element.querySelector("video").pause(); } }); } } });

    使滑动范围更新当前时间 (Make sliding the range update the current time)

    问题 (The problem)

    In this section we will:

    在本节中,我们将:

    Remove the native controls from the video player. We don’t need them anymore!

    从视频播放器中删除本机控件。 我们不再需要它们了! Make it so when a user moves the range slider, the video position updates.

    当用户移动范围滑块时,视频位置会更新。

    你需要知道的 (What you need to know)

    Similar to when we made the play/pause button play or pause the video, we will want to update the currentTime property and then listen to when currentTime changes and update the <video> element’s currentTime as a side-effect.

    类似于使播放/暂停按钮播放或暂停视频时 ,我们将要更新currentTime属性,然后在currentTime更改时进行监听,并更新<video>元素的currentTime作为副作用 。

    This time, we need to translate the sliders values between 0 and 1 to currentTime values. We can do this by creating a percentComplete setter that updates currentTime like:

    这次,我们需要将0到1之间的滑块值转换为currentTime值。 为此,我们可以创建一个percentComplete 设置器来更新currentTime例如:

    ViewModel: { // ... get percentComplete() { return this.currentTime / this.duration; }, set percentComplete(newVal) { this.currentTime = newVal * this.duration; }, // ... }

    Use key:bind to two-way bind a value to a ViewModel property:

    使用key:bind双向绑定一个值到ViewModel属性:

    <input value:bind="someViewModelProperty"/>

    解决方案 (The solution)

    Update the JavaScript tab to:

    将JavaScript标签更新为:

    import {Component} from "//unpkg.com/can@5/core.mjs"; Component.extend({ tag: "video-player", view: ` <video {{!👀}} on:play="play()" on:pause="pause()" on:timeupdate="updateTimes(scope.element)" on:loadedmetadata="updateTimes(scope.element)"> <source src="{{src}}"/> </video> <div> <button on:click="togglePlay()"> {{#if(playing)}} Pause {{else}} Play {{/if}} </button> <input type="range" value="0" max="1" step="any" value:bind="percentComplete"/> {{!👀}} <span>{{formatTime(currentTime)}}</span> / <span>{{formatTime(duration)}} </span> </div> `, ViewModel: { src: "string", playing: "boolean", duration: "number", currentTime: "number", get percentComplete() { return this.currentTime / this.duration; }, set percentComplete(newVal) { //👀 this.currentTime = newVal * this.duration; //👀 }, //👀 updateTimes(videoElement) { this.currentTime = videoElement.currentTime || 0; this.duration = videoElement.duration; }, formatTime(time) { if (time === null || time === undefined) { return "--"; } const minutes = Math.floor(time / 60); let seconds = Math.floor(time - minutes * 60); if (seconds < 10) { seconds = "0" + seconds; } return minutes + ":" + seconds; }, play() { this.playing = true; }, pause() { this.playing = false; }, togglePlay() { this.playing = !this.playing; }, connectedCallback(element) { this.listenTo("playing", function(event, isPlaying) { if (isPlaying) { element.querySelector("video").play(); } else { element.querySelector("video").pause(); } }); this.listenTo("currentTime", function(event, currentTime) { //👀 const videoElement = element.querySelector("video"); //👀 if (currentTime !== videoElement.currentTime) { //👀 videoElement.currentTime = currentTime; //👀 } //👀 }); //👀 } } });

    结果 (Result)

    When finished, you should see something like the following JS Bin:

    完成后,您应该会看到类似以下JS Bin的内容:

    演示地址

    翻译自: https://davidwalsh.name/custom-html5-video

    自定义视频播放控件样式

    相关资源:jQuery自定义视频弹幕插件,网页自适应视频播放器
    Processed: 0.009, SQL: 9