頭條創(chuàng)作挑戰(zhàn)賽#
本文同步本人掘金平臺(tái)的文章:https://juejin.cn/post/7084784818247958535
上一篇文章是 Angular 項(xiàng)目實(shí)現(xiàn)權(quán)限控制。最近自己在網(wǎng)上看到別人使用 vue 進(jìn)行自定義 video 的操縱。加上不久前實(shí)現(xiàn)了 angular 自定義 video 的相關(guān)需求, 遂來(lái)記錄一下,作為交流思考
實(shí)現(xiàn)的功能如下:
如圖:
下面我們來(lái)一一實(shí)現(xiàn):
這里的重點(diǎn)不在布局,我們簡(jiǎn)單來(lái)定義一下:
<!-- app.component.html -->
<div class="video-page">
<div class="video-tools">
<button nz-button nzType="primary" (click)="play('btn')" style="margin-right: 12px;">播放 ?</button>
<button nz-button nzType="primary" (click)="pause('btn')">暫停 ?</button>
<ng-container>
<button nz-button nz-dropdown [nzDropdownMenu]="menuForward" nzPlacement="bottomCenter" style="margin: 0 12px;">快進(jìn) ?</button>
<nz-dropdown-menu #menuForward="nzDropdownMenu">
<ul nz-menu>
<li nz-menu-item (click)="forwardSecond(10)">快進(jìn) 10 s</li>
<li nz-menu-item (click)="forwardSecond(20)">快進(jìn) 20 s</li>
</ul>
</nz-dropdown-menu>
</ng-container>
<ng-container>
<button nz-button nz-dropdown [nzDropdownMenu]="menuBack" nzPlacement="bottomCenter">快退 ?</button>
<nz-dropdown-menu #menuBack="nzDropdownMenu">
<ul nz-menu>
<li nz-menu-item (click)="retreatSecond(10)">快退 10 s</li>
<li nz-menu-item (click)="retreatSecond(20)">快退 20 s</li>
</ul>
</nz-dropdown-menu>
</ng-container>
<ng-container>
<button nz-button nz-dropdown [nzDropdownMenu]="speedUp" nzPlacement="bottomCenter" style="margin: 0 12px;">倍速 ?</button>
<nz-dropdown-menu #speedUp="nzDropdownMenu">
<ul nz-menu>
<li nz-menu-item (click)="speedUpVideo(1)">正常</li>
<li nz-menu-item (click)="speedUpVideo(2)">2 倍</li>
<li nz-menu-item (click)="speedUpVideo(4)">4 倍</li>
</ul>
</nz-dropdown-menu>
</ng-container>
<button nz-button nzType="primary" (click)="openOrCloseVoice()">聲音開(kāi) / 聲音關(guān) ?</button>
<button nz-button nzType="primary" style="margin: 0 12px;" (click)="toFullScreen()">全屏 ?</button>
<br />
<button nz-button nzType="primary" style="margin-top: 12px;" (click)="entryInPicture()">進(jìn)入畫(huà)中畫(huà) ?? 安卓平板不支持</button>
<button nz-button nzType="primary" style="margin: 12px 12px 0 12px;" (click)="exitInPicture()">退出畫(huà)中畫(huà) ?? 安卓平板不支持</button>
<br />
<div style="display: flex; justify-content: flex-start; align-items: center; margin: 12px 0;">
經(jīng)過(guò)時(shí)長(zhǎng) / 總時(shí)長(zhǎng) : ? {{ currentTime }} / {{ totalTime }}
</div>
<!-- 進(jìn)度條 -->
<div style="display: flex; justify-content: flex-start; align-items: center; margin: 12px 0;">
進(jìn)度條:?
<div
class="custom-video_control-bg"
(mousedown)="handleProgressDown($event)"
(mousemove)="handleProgressMove($event)"
(mouseup)="handleProgressUp($event)"
>
<div
class="custom-video_control-bg-outside"
id="custom-video_control-bg-outside"
>
<span
class="custom-video_control-bg-inside"
id="custom-video_control-bg-inside"
></span>
<span
class="custom-video_control-bg-inside-point"
id="custom-video_control-bg-inside-point"
></span>
</div>
</div>
</div>
<div style="display: flex; justify-content: flex-start; align-items: center; margin: 12px 0;">
聲音條:?
<div class="custom-video_control-voice">
<span class="custom-video_control-voice-play">
<i nz-icon nzType="sound" nzTheme="outline"></i>
</span>
<div
class="custom-video_control-voice-bg"
id="custom-video_control-voice-bg"
(mousedown)="handleVolProgressDown($event)"
(mousemove)="handleVolProgressMove($event)"
(mouseup)="handleVolProgressUp($event)"
>
<div
class="custom-video_control-voice-bg-outside"
id="custom-video_control-voice-bg-outside"
>
<span
class="custom-video_control-voice-bg-inside"
id="custom-video_control-voice-bg-inside"
></span>
<span
class="custom-video_control-voice-bg-point"
id="custom-video_control-voice-bg-point"
></span>
</div>
</div>
</div>
</div>
</div>
<div class="video-content">
<video id="video" class="video" style="width: 100%" poster="assets/poster.png">
<source type="video/mp4" src="assets/demo.mp4">
Sorry, your browser doesn't support.
</video>
</div>
</div>
復(fù)制代碼
這里使用了 angular ant design,之前寫(xiě)了一篇相關(guān)文章,還不熟悉的讀者可前往 Angular 結(jié)合 NG-ZORRO 快速開(kāi)發(fā)
這里直接調(diào)用 video 對(duì)象的方法 play() 和 pause():
// app.component.ts
// 播放按鈕事件
play(flag: string | undefined) {
if(flag) this.videoState.playState=true
this.videoState.play=true
this.video.play()
}
// 暫停按鈕事件
pause(flag: string | undefined): void {
if(flag) this.videoState.playState=false
this.video.pause()
this.videoState.play=false
}
復(fù)制代碼
這里自定義的 play 和 pause 方法加上了一個(gè)標(biāo)志,對(duì)下下面要講的進(jìn)度條的控制有幫助,上面的代碼可以更加簡(jiǎn)潔,讀者可以簡(jiǎn)寫(xiě)下。
這里的快退,快進(jìn)和倍速設(shè)置了不同的選項(xiàng),通過(guò)參數(shù)進(jìn)行傳遞:
// app.component.ts
// 快進(jìn)指定的時(shí)間
forwardSecond(second: number): void {
this.video.currentTime +=second; // 定位到當(dāng)前的播放時(shí)間 currentTime
}
// 后退指定的時(shí)間
retreatSecond(second: number): void {
this.video.currentTime -=second
}
// 倍速
speedUpVideo(multiple: number): void {
this.video.playbackRate=multiple; // 設(shè)定當(dāng)前的倍速 playbackRate
}
復(fù)制代碼
聲音的開(kāi)關(guān)使用 video 的 muted 屬性即可:
// app.component.ts
// 開(kāi)或關(guān)聲音
openOrCloseVoice(): void {
this.video.muted=!this.video.muted;
}
復(fù)制代碼
全屏的操作也是很簡(jiǎn)單,使用 webkitRequestFullScreen
// app.component.ts
// 全屏操作
toFullScreen(): void {
this.video.webkitRequestFullScreen()
}
復(fù)制代碼
全屏后,按 esc 可退出全屏
畫(huà)中畫(huà)相當(dāng)于彈窗縮小視頻~
// app.component.ts
// 進(jìn)入畫(huà)中畫(huà)
entryInPicture(): void {
this.video.requestPictureInPicture()
this.video.style.display="none"
}
// 退出畫(huà)中畫(huà)
exitInPicture(): void {
if(this.document.pictureInPictureElement) {
this.document.exitPictureInPicture()
this.video.style.display="block"
}
}
復(fù)制代碼
設(shè)置 video 的樣式,是為了看起來(lái)不突兀...
記錄視頻的總時(shí)長(zhǎng)和視頻當(dāng)前的播放時(shí)長(zhǎng)。我們已經(jīng)來(lái)組件的時(shí)候就獲取視頻的元信息,得到總時(shí)長(zhǎng);在視頻播放的過(guò)程中,更新當(dāng)前時(shí)長(zhǎng)。
// app.component.ts
// 初始化 video 的相關(guān)的事件
initVideoData(): void {
// 獲取視頻的總時(shí)長(zhǎng)
this.video.addEventListener('loadedmetadata', ()=> {
this.totalTime=this.formatTime(this.video.duration)
})
// 監(jiān)聽(tīng)時(shí)間發(fā)生更改
this.video.addEventListener('timeupdate', ()=> {
this.currentTime=this.formatTime(this.video.currentTime) // 當(dāng)前播放的時(shí)間
})
}
復(fù)制代碼
formatTime 是格式化函數(shù)
監(jiān)聽(tīng)鼠標(biāo)的點(diǎn)擊,移動(dòng),松開(kāi)的事件,對(duì)視頻的播放時(shí)間和總事件進(jìn)行相除,計(jì)算百分比。
// app.component.ts
// 進(jìn)度條鼠標(biāo)按下
handleProgressDown(event: any): void {
this.videoState.downState=true
this.pause(undefined);
this.videoState.distance=event.clientX + document.documentElement.scrollLeft - this.videoState.leftInit;
}
// 進(jìn)度條 滾動(dòng)條移動(dòng)
handleProgressMove(event: any): void {
if(!this.videoState.downState) return
let distanceX=(event.clientX + document.documentElement.scrollLeft) - this.videoState.leftInit
if(distanceX > this.processWidth) { // 容錯(cuò)處理
distanceX=this.processWidth;
}
if(distanceX < 0) { // 容錯(cuò)處理
distanceX=0
}
this.videoState.distance=distanceX
this.video.currentTime=this.videoState.distance / this.processWidth * this.video.duration
}
// 進(jìn)度條 鼠標(biāo)抬起
handleProgressUp(event: any): void {
this.videoState.downState=false
// 視頻播放
this.video.currentTime=this.videoState.distance / this.processWidth * this.video.duration
this.currentTime=this.formatTime(this.video.currentTime)
if(this.videoState.playState) {
this.play(undefined)
}
}
復(fù)制代碼
這里需要計(jì)算進(jìn)度條的位置,來(lái)獲取點(diǎn)擊進(jìn)度條的百分比,之后更新視頻的當(dāng)前播放時(shí)間。當(dāng)然,我們還得有容錯(cuò)處理,比如進(jìn)度條為負(fù)數(shù)時(shí)候,當(dāng)前播放時(shí)間為0。
我們實(shí)現(xiàn)了播放進(jìn)度條的操作,對(duì)聲音進(jìn)度條的實(shí)現(xiàn)就很容易上手了。聲音進(jìn)度條也是監(jiān)聽(tīng)鼠標(biāo)的點(diǎn)擊,移動(dòng),松開(kāi)。不過(guò),這次我們處理的是已知聲音 div 的高度。
// app.component.ts
// 聲音條 鼠標(biāo)按下
handleVolProgressDown(event: any) {
this.voiceState.topInit=this.getOffset(this.voiceProOut, undefined).top
this.volProcessHeight=this.voiceProOut.clientHeight
this.voiceState.downState=true //按下鼠標(biāo)標(biāo)志
this.voiceState.distance=this.volProcessHeight - (event.clientY + document.documentElement.scrollTop - this.voiceState.topInit)
}
// 聲音 滾動(dòng)條移動(dòng)
handleVolProgressMove(event: any) {
if(!this.voiceState.downState) return
let disY=this.voiceState.topInit + this.volProcessHeight - (event.clientY + document.documentElement.scrollTop)
if(disY > this.volProcessHeight - 2) { // 容錯(cuò)處理
disY=this.volProcessHeight - 2
}
if(disY < 0) { // 容錯(cuò)處理
disY=0
}
this.voiceState.distance=disY
this.video.volume=this.voiceState.distance / this.volProcessHeight
this.videoOption.volume=Math.round(this.video.volume * 100)
}
// 聲音 鼠標(biāo)抬起
handleVolProgressUp(event: any) {
this.voiceState.downState=false //按下鼠標(biāo)標(biāo)志
let voiceRate=this.voiceState.distance / this.volProcessHeight
if(voiceRate > 1) {
voiceRate=1
}
if(voiceRate < 0) {
voiceRate=0
}
this.video.volume=voiceRate
this.videoOption.volume=Math.round(this.video.volume * 100); // 賦值給視頻聲音
}
復(fù)制代碼
如圖:
完成了上面的內(nèi)容,我們以一個(gè) gif 圖來(lái)展示效果:
全屏,聲音和畫(huà)中畫(huà)比較難截圖,Gif 上體現(xiàn)不來(lái)
詳細(xì)的代碼,請(qǐng)前往 video-ng 獲取。
【完】?
篇介紹了前端入門(mén)——html 中如何使用圖片,今天講下如何使用視頻和音頻等多媒體元素,它們能讓你的網(wǎng)頁(yè)更加豐富,讀者相對(duì)于文字圖片更愿意觀看視頻和音頻或其它多媒體。在本教程中,您將了解到不同的多媒體格式,以及如何在您的網(wǎng)頁(yè)中使用它們。
是多種媒體的綜合,一般包括文本,聲音和圖像等多種媒體形式。在計(jì)算機(jī)系統(tǒng)中,多媒體指組合兩種或兩種以上媒體的一種人機(jī)交互式信息交流和傳播媒體。使用的媒體包括文字、圖片、照片、聲音、動(dòng)畫(huà)和影片,以及程式所提供的互動(dòng)功能。
在因特網(wǎng)上,您會(huì)經(jīng)常發(fā)現(xiàn)嵌入網(wǎng)頁(yè)中的多媒體元素,現(xiàn)代瀏覽器已支持多種多媒體格式。
多媒體元素(比如視頻和音頻)存儲(chǔ)于媒體文件中。多媒體元素也擁有帶有不同擴(kuò)展名字的文件格式,比如 .swf、.wmv、.mp3 以及 .mp4。具體有哪些格式可以參考 w3cshool 網(wǎng)站的介紹,https://www.w3cschool.cn/html5/html5-video.html ,https://www.w3cschool.cn/html5/html5-audio.html。
直到現(xiàn)在,網(wǎng)頁(yè)上仍然不存在一項(xiàng)顯示視頻的標(biāo)準(zhǔn)。今天,大多數(shù)視頻是通過(guò)插件(比如 Flash)來(lái)顯示的。然而,并非所有瀏覽器都擁有同樣的插件。HTML5 規(guī)定了一種通過(guò) video 元素來(lái)包含視頻的標(biāo)準(zhǔn)方法。
語(yǔ)法如下:
<video width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
<source src="movie.ogg" type="video/ogg">
您的瀏覽器不支持Video標(biāo)簽。
</video>
<video> 元素提供了播放、暫停和音量控件來(lái)控制視頻。
同時(shí) <video> 元素也提供了 width 和 height 屬性控制視頻的尺寸。如果設(shè)置的高度和寬度,所需的視頻空間會(huì)在頁(yè)面加載時(shí)保留。如果沒(méi)有設(shè)置這些屬性,瀏覽器不知道視頻的大小,瀏覽器就不能在加載時(shí)保留特定的空間,頁(yè)面就會(huì)根據(jù)原始視頻的大小而改變。
<video> 與 </video> 標(biāo)簽之間插入的內(nèi)容是提供給不支持 video 元素的瀏覽器顯示的。元素可以鏈接不同的視頻文件。瀏覽器將使用第一個(gè)可識(shí)別的格式。一個(gè)頁(yè)面可以使用多個(gè)<video> 標(biāo)簽,<video> 元素支持三種視頻格式: MP4, WebM, 和 Ogg。
顯示效果:
和視頻一樣沒(méi)有統(tǒng)一的標(biāo)準(zhǔn),各個(gè)瀏覽器都不一樣。HTML5 規(guī)定了在網(wǎng)頁(yè)上嵌入音頻元素的標(biāo)準(zhǔn),即使用 <audio> 元素。通過(guò)使用HTML5中的audio功能,你可以實(shí)現(xiàn)與flash相同的功能,即回放、跳轉(zhuǎn)、緩沖等。
語(yǔ)法如下:
<audio controls>
<source src="horse.ogg" type="audio/ogg">
<source src="horse.mp3" type="audio/mpeg">
您的瀏覽器不支持 audio 元素。
</audio>
control 屬性供添加播放、暫停和音量控件。在<audio> 與 </audio> 之間你需要插入瀏覽器不支持的<audio>元素的提示文本 。允許使用多個(gè) <source> 元素。<source> 元素可以鏈接不同的音頻文件,瀏覽器將使用第一個(gè)支持的音頻文件。目前, <audio>元素支持三種音頻格式文件: MP3, Wav, 和 Ogg。
顯示效果:
插件(Plug-in)是擴(kuò)展瀏覽器標(biāo)準(zhǔn)功能的計(jì)算機(jī)程序,插件被設(shè)計(jì)用于許多不同的目的:
1、<object> 元素
<object> 元素定義 HTML 文檔中的嵌入式對(duì)象。
它旨在將插件(例如 Java applet、PDF 閱讀器和 Flash 播放器)嵌入網(wǎng)頁(yè)中,但也可以用于將 HTML 包含在 HTML 中。
如下:
插入一個(gè)網(wǎng)頁(yè)片段
<object width="100%" height="500px" data="snippet.html"></object>
或者插入一個(gè)圖片
<object data="audi.jpeg"></object>
播放一個(gè)視頻
<object width="420" height="360"
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
codebase="http://www.apple.com/qtactivex/qtplugin.cab">
<param name="src" value="movie.mp4">
<param name="controller" value="true">
</object>
播放一個(gè)音頻
<object height="100" width="100" data="song.mp3"></object>
2、<embed> 元素
<embed> 元素也可定義了 HTML 文檔中的嵌入式對(duì)象。這是一個(gè) HTML5 標(biāo)簽,在 HTML4 中是非法的,但是所有瀏覽器中都有效。
插入一個(gè)flash文件
<embed width="400" height="50" src="bookmark.swf">
插入html片段
<embed width="100%" height="500px" src="snippet.html">
播放一個(gè)音頻
<embed height="100" width="100" src="song.mp3" />
插入一個(gè)圖片
<embed src="audi.jpeg">
注意:
大多數(shù)瀏覽器不再支持 Java 小程序和插件。
大多數(shù)現(xiàn)代瀏覽器關(guān)閉了對(duì) Flash 的支持。
我們可以使用 <video> 和 <audio> 標(biāo)簽來(lái)顯示視頻和音頻
如下視頻代碼,HTML 5 <video> 元素會(huì)嘗試播放以 mp4、ogg 或 webm 格式中的一種來(lái)播放視頻。如果均失敗,則回退到 <embed> 元素。
HTML 5 + <object> + <embed> 是最好的解決辦法。
<video width="320" height="240" controls="controls">
<source src="movie.mp4" type="video/mp4" />
<source src="movie.ogg" type="video/ogg" />
<source src="movie.webm" type="video/webm" />
<object data="movie.mp4" width="320" height="240">
<embed src="movie.swf" width="320" height="240" />
</object>
</video>
如下音頻代碼,HTML5 <audio> 元素會(huì)嘗試以 mp3 或 ogg 來(lái)播放音頻。如果失敗,代碼將回退嘗試 <embed> 元素。
HTML 5 + <embed> 是最好的解決辦法。
<audio controls="controls" height="100" width="100">
<source src="song.mp3" type="audio/mp3" />
<source src="song.ogg" type="audio/ogg" />
<embed height="100" width="100" src="song.mp3" />
</audio>
到此你以及了解了如何在網(wǎng)頁(yè)中使用視頻音頻及其它多媒體控件,趕快自己試試,祝你學(xué)習(xí)愉快。
參考文獻(xiàn):https://www.w3school.com.cn/html/html_video.asp
上篇:前端入門(mén)——html 中如何使用圖片
下篇:前端入門(mén)——html 表格的使用
網(wǎng)頁(yè)開(kāi)發(fā)中,跟蹤用戶與多媒體內(nèi)容(如視頻)的互動(dòng)是一項(xiàng)常見(jiàn)需求。無(wú)論是教育平臺(tái)、數(shù)據(jù)分析,還是用戶參與度統(tǒng)計(jì),監(jiān)控用戶如何觀看視頻內(nèi)容都能提供寶貴的見(jiàn)解。這篇文章將探索如何使用JavaScript實(shí)現(xiàn)視頻播放時(shí)長(zhǎng)的跟蹤。
我們的目標(biāo)是跟蹤用戶觀看視頻的總時(shí)長(zhǎng),包括暫停的時(shí)間,并將這些信息更新到后臺(tái)系統(tǒng)。我們將通過(guò)捕獲播放、暫停和結(jié)束等事件來(lái)計(jì)算觀看時(shí)間。
讓我們來(lái)分解一下實(shí)現(xiàn)的關(guān)鍵方面:
1. HTML結(jié)構(gòu)
我們將使用HTML5的<video>標(biāo)簽將視頻嵌入到網(wǎng)頁(yè)中。每個(gè)視頻元素都將有一個(gè)唯一的標(biāo)識(shí)符,以便在JavaScript中輕松訪問(wèn)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>視頻播放時(shí)長(zhǎng)跟蹤</title>
</head>
<body>
<!-- 視頻容器 -->
<video id="video_content1" width="640" height="360" controls>
<!-- 視頻源 -->
<source src="your_video_source.mp4" type="video/mp4" />
</video>
<!-- 包含JavaScript代碼 -->
<script src="your_script.js"></script>
</body>
</html>
2. JavaScript實(shí)現(xiàn)
在JavaScript文件(your_script.js)中,我們將處理視頻事件并計(jì)算總的觀看時(shí)間。
// 獲取視頻元素
let videoMat="your_video_source.mp4";
let source=document.createElement('source');
let video=document.getElementById('video_content1');
// 設(shè)置視頻源
source.src=videoMat;
source.type='video/mp4';
// 將源附加到視頻元素
if (video) {
video.appendChild(source);
// 初始化變量
let startTime=null;
let lastUpdateTime=null;
let totalElapsedTime=0;
// 'play'事件監(jiān)聽(tīng)器
video.addEventListener('play', function () {
startTime=new Date();
lastUpdateTime=startTime;
console.log('視頻正在播放。開(kāi)始時(shí)間:', startTime);
});
// 'timeupdate'事件監(jiān)聽(tīng)器
video.addEventListener('timeupdate', function () {
if (!video.paused && startTime !==null) {
const currentTime=new Date();
const elapsedSinceLastUpdate=(currentTime - lastUpdateTime) / 1000;
totalElapsedTime +=elapsedSinceLastUpdate;
lastUpdateTime=currentTime;
console.log("從開(kāi)始到現(xiàn)在的觀看時(shí)間: " + totalElapsedTime + " 秒");
}
});
// 'pause'事件監(jiān)聽(tīng)器
video.addEventListener('pause', function () {
// 僅當(dāng)視頻已在播放時(shí)存儲(chǔ)暫停時(shí)間
if (startTime !==null) {
const pausedTime=video.currentTime;
console.log('視頻已暫停。暫停時(shí)刻:', pausedTime);
checkAndUpdateItem(totalElapsedTime, 1, 'your_video_title');
}
});
// 'ended'事件監(jiān)聽(tīng)器
video.addEventListener('ended', function () {
// 視頻播放已結(jié)束
checkAndUpdateItem(totalElapsedTime, 1, 'your_video_title');
});
// 'play'事件監(jiān)聽(tīng)器(從暫停時(shí)間繼續(xù)播放)
video.addEventListener('play', function () {
// 如果視頻之前暫停,繼續(xù)從暫停時(shí)刻播放
if (startTime !==null) {
video.currentTime=video.currentTime;
}
});
}
解釋
實(shí)現(xiàn)視頻播放時(shí)長(zhǎng)的跟蹤可以增強(qiáng)用戶分析,提供有關(guān)用戶參與度和內(nèi)容受歡迎程度的見(jiàn)解。這里提供的JavaScript代碼為您集成視頻跟蹤到網(wǎng)頁(yè)應(yīng)用中提供了基礎(chǔ)。
記得將‘your_video_source.mp4’和‘your_video_title’替換為實(shí)際的視頻源和標(biāo)題。
祝您編碼愉快!
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。