最近在移動(dòng)端項(xiàng)目用到了video標(biāo)簽展示視頻恒削,原本以為作為html5標(biāo)準(zhǔn)一員的video到了今天兼容性應(yīng)該沒什么問題了,可一用才知道還是有些坑的......那么在這里就由淺入深的論述一下使用video的心得吧(一些眾所周知的常用屬性和我沒怎么用過的在此均省略不表)尾序。
屬性
-
src
要播放的視頻的 URL蔓同。只支持3種格式:MP4、WebM蹲诀、Ogg斑粱。另外src除了可以使用放在服務(wù)器的絕對路徑和項(xiàng)目中的相對路徑(對于本地路徑在PC端有一些限制,移動(dòng)端貌似無法取到本地視頻)脯爪,還支持 base64碼(需添加前綴data:video/mp4;base64,
注意有逗號) -
poster
規(guī)定視頻正在下載時(shí)顯示的圖像则北,直到用戶點(diǎn)擊播放按鈕。(也就是視頻播放之前顯示的一個(gè)預(yù)覽圖)其值和img標(biāo)簽的src屬性相同痕慢,填上一個(gè)圖片路徑或者base64尚揣。 -
playsinline
webkit-playsinline
視頻在移動(dòng)端播放時(shí)會(huì)自動(dòng)全屏,而這個(gè)屬性就是為了阻止全屏動(dòng)作的掖举,添加-webkit-前綴增加在ios safari上的兼容性快骗。(只用寫上屬性名就行,和autoplay,loop之類的類似) -
muted
如果出現(xiàn)該屬性塔次,視頻的音頻輸出為靜音方篮。 -
autoplay
自動(dòng)播放,但是在ios上無法執(zhí)行自動(dòng)播放......(添加muted
可以自動(dòng)播放)需要用戶執(zhí)行play方法励负。(具體可參考視頻播放--踩坑小計(jì))
以上幾種屬性是寫video標(biāo)簽時(shí)經(jīng)常設(shè)置的幾種屬性藕溅,以下的幾種則一般是需要在js中獲取的屬性,以便進(jìn)行一些操作继榆。
-
networkState
返回音頻/視頻的當(dāng)前網(wǎng)絡(luò)狀態(tài)(activity)巾表。
返回值如下- 0 = NETWORK_EMPTY - 音頻/視頻尚未初始化
- 1 = NETWORK_IDLE - 音頻/視頻是活動(dòng)的且已選取資源,但并未使用網(wǎng)絡(luò)
- 2 = NETWORK_LOADING - 瀏覽器正在下載數(shù)據(jù)
- 3 = NETWORK_NO_SOURCE - 未找到音頻/視頻來源
一般用到的就是1和2,當(dāng)值為1的時(shí)候表示視頻已經(jīng)可以播放了(至少是當(dāng)前幀已經(jīng)加載好了略吨,不過ios此時(shí)播放可能會(huì)白屏)集币,值為2的時(shí)候播放下一幀會(huì)卡住(安卓)或者白屏(ios)。
注意:
- 返回的值是
Number
類型,這使得在使用mint-ui這類的ui框架調(diào)試時(shí)可能會(huì)Toast
一個(gè)空值,需要先轉(zhuǎn)為字符串才能顯示翠忠。 - 關(guān)于ios上返回2繼續(xù)播放會(huì)白屏的問題(僅僅出現(xiàn)在視頻第一次點(diǎn)擊播放的時(shí)候)鞠苟,這里我暫時(shí)沒發(fā)現(xiàn)是什么原因?qū)е碌模ㄓ锌赡苁且曨l太大??)
-
readyState
readyState 屬性返回音頻/視頻的當(dāng)前就緒狀態(tài)偶妖。
返回值如下- 0 = HAVE_NOTHING - 沒有關(guān)于音頻/視頻是否就緒的信息
- 1 = HAVE_METADATA - 關(guān)于音頻/視頻就緒的元數(shù)據(jù)
- 2 = HAVE_CURRENT_DATA - 關(guān)于當(dāng)前播放位置的數(shù)據(jù)是可用的姜凄,但沒有足夠的數(shù)據(jù)來播放下一幀/毫秒
- 3 = HAVE_FUTURE_DATA - 當(dāng)前及至少下一幀的數(shù)據(jù)是可用的
- 4 = HAVE_ENOUGH_DATA - 可用數(shù)據(jù)足以開始播放
這里的返回值也是Number
類型的
我在項(xiàng)目中先使用的就是這個(gè)屬性,在返回1或2的時(shí)候代表剛進(jìn)入這個(gè)頁面瀏覽器還在加載視頻趾访,返回4則代表整個(gè)視頻已經(jīng)加載完畢了态秧。可是我發(fā)現(xiàn)ios在返回3的時(shí)候立即播放還是有時(shí)會(huì)出現(xiàn)白屏扼鞋,而安卓在返回3的時(shí)候是可以播放的申鱼,因此最后我選擇了使用networkState
來對視頻加載狀態(tài)進(jìn)行判斷。
- 不可思議的
currentTime
定義是這么說的:設(shè)置或返回音頻/視頻播放的當(dāng)前位置(以秒計(jì))云头。當(dāng)設(shè)置該屬性時(shí)捐友,播放會(huì)跳躍到指定的位置。
而我使用這個(gè)屬性來判斷視頻是否能連續(xù)播放溃槐,當(dāng)視頻播放的時(shí)候如果這個(gè)屬性的值‘走動(dòng)了’匣砖,可以認(rèn)為視頻已經(jīng)可以播放下一幀了。感謝h5 video 移動(dòng)端填坑記這篇文章提供的方法昏滴。
方法
我一般用到的方法也就是play()
,pause()
這里不過多贅述猴鲫。
事件
-
canplay
當(dāng)瀏覽器能夠開始播放指定的音頻/視頻時(shí),會(huì)發(fā)生 canplay 事件谣殊。
乍一看有了這個(gè)事件似乎就不需要上面各種state去判斷視頻能否播放了拂共,可惜萬惡的ios不支持這個(gè)事件,實(shí)測第一次進(jìn)入頁面ios在canplay事件觸發(fā)的時(shí)候視頻的networkState
仍然處于2這個(gè)狀態(tài)姻几,也就是還未加載完成...... -
progress
當(dāng)瀏覽器正在下載指定的音頻/視頻時(shí)宜狐,會(huì)發(fā)生 progress 事件。
我使用這個(gè)事件的方向可能有點(diǎn)‘歪門邪道’蛇捌,眾所周知一個(gè)視頻在頁面加載的時(shí)候等待時(shí)間或許會(huì)有點(diǎn)長抚恒,一般網(wǎng)站使用的是一個(gè)圖片或者gif去代替video標(biāo)簽,當(dāng)視頻加載好了的時(shí)候就讓video顯示出來豁陆。而上面的canplay
用不了柑爸,所以我抱著試試的想法在progress事件觸發(fā)的時(shí)候讓loading圖隱藏起來(loading圖默認(rèn)顯示),結(jié)果實(shí)際效果讓我很滿意盒音,progress事件觸發(fā)的時(shí)候視頻的poster
已經(jīng)顯示出來了,我初步判斷第一次觸發(fā)這個(gè)事件應(yīng)該是視頻第一幀可能前幾幀都加載好了馅而。 -
timeupdate
timeupdate 事件在音頻/視頻(audio/video)的播放位置發(fā)生改變時(shí)觸發(fā)祥诽。
這個(gè)事件一看就是結(jié)合上面的currentTime
屬性用的。在后文我會(huì)詳述瓮恭。 -
waiting
waiting 事件在視頻由于需要緩沖下一幀而停止時(shí)觸發(fā)雄坪。
在我的項(xiàng)目用它主要是因?yàn)閕os白屏的時(shí)候會(huì)觸發(fā)這個(gè)事件......這樣我可以在這個(gè)事件中讓視頻暫停。 -
ended
ended 事件在音頻/視頻(audio/video)播放完成后觸發(fā)屯蹦。
由于我的視頻沒有用loop
屬性所以我使用這個(gè)事件來提示用戶視頻播放結(jié)束维哈。
應(yīng)用
項(xiàng)目基于vue绳姨,ui框架使用的是mint-ui,還是直接上代碼吧...
<div class="video-con fl">
<div class="video" @click="$_videoFromApp_getVideoRecord">
<!-- 后臺(tái)沒有視頻時(shí)顯示的內(nèi)容 -->
<img class="no-video" v-show="videoFromApp_noVideo" :src="require('@/images/icon/video.png')" alt="">
<div class="bg-gray" v-show="videoFromApp_noVideo"></div>
<!-- 視頻處于暫停時(shí)顯示的內(nèi)容 -->
<div v-show="!videoFromApp_playing">
<img class="play-video" v-show="!videoFromApp_noVideo"
:src="require('@/images/icon/play-video.png')" alt="">
<span class="play-time" v-show="!videoFromApp_noVideo">{{videoFromApp_videoTime}}</span>
</div>
<!-- loading -->
<mt-spinner v-show="videoFromApp_loading" class="loading-css" type="fading-circle"></mt-spinner>
<!-- 視頻 -->
<video webkit-playsinline playsinline
ref="indentVideo"
class="real-video"
:src="videoFromApp_videoSrc"
v-show="!videoFromApp_noVideo"
:poster="videoFromApp_videoImg"
@progress="$_videoFromApp_hasVideo"
@waiting="$_videoFromApp_waiting"
@ended="$_videoFromApp_endVideo"></video>
</div>
</div>
js部分
<script>
......
//播放視頻
$_videoFromApp_getVideoRecord(v){
......
if (this.videoFromApp_playing) {
this.videoFromApp_playing = false;
this.$refs.indentVideo.pause();
} else {
this.videoFromApp_playing = true;
let video = this.$refs.indentVideo;
let networkState = this.$refs.indentVideo.networkState;
let readyState = this.$refs.indentVideo.readyState;
if(networkState==1){
this.$refs.indentVideo.play();
this.videoFromApp_loading = true;
video.ontimeupdate = ()=>{
if(video.currentTime > 0.1){
this.videoFromApp_loading = false;
}
}
}else{
Toast({
message: '拼命加載中阔挠,請稍后',
position: 'bottom',
duration: 1000
});
this.videoFromApp_playing = false;
}
}
},
//視頻初步加載
$_videoFromApp_hasVideo(){
this.videoFromApp_loading = false;
},
//緩沖
$_videoFromApp_waiting(){
this.$refs.indentVideo.pause();
this.videoFromApp_playing = false;
Toast({
message: '拼命加載中飘庄,請稍后',
position: 'bottom',
duration: 1000
});
},
//視頻播放完成
$_videoFromApp_endVideo(){
this.videoFromApp_playing = false;
},
</script>
在此就簡述一下播放視頻方法,當(dāng)視頻處于暫停狀態(tài)時(shí)购撼,點(diǎn)擊播放跪削,判斷networkState
,當(dāng)值為1的時(shí)候允許播放,此時(shí)監(jiān)聽timeupdate
事件迂求,(使用addEventListener
監(jiān)聽會(huì)有毛病碾盐,如果看過我之前的一篇關(guān)于iframe的文章應(yīng)該會(huì)有所了解)先加上loading,如果currentTime > 0.1
代表視頻已經(jīng)能流暢播放了揩局,再隱藏loading毫玖。這個(gè)過程中如果無法播放的話就會(huì)走到waitting事件中,視頻會(huì)暫停凌盯。
再次點(diǎn)擊繼續(xù)重復(fù)這個(gè)過程直到視頻可以正常播放孕豹。
寫在后面
其實(shí)吧本文寫作的真正目的是為了拋磚引玉,文中所寫的一些方法只為解決項(xiàng)目中的燃眉之急十气,文中部分內(nèi)容僅僅為個(gè)人觀點(diǎn)励背,如果各位讀者發(fā)現(xiàn)了文中的缺陷與問題,歡迎在評論區(qū)留言探討砸西。
======================
2018-11-12更新
關(guān)于播放白屏的原因:最近發(fā)現(xiàn)安卓部分手機(jī)播放視頻又白屏了叶眉,最終總結(jié)出了避免白屏的方法。
1.播放視頻的格式最好是mp4 avc h.264格式的芹枷,不是這種格式的視頻用video播放很可能白屏衅疙。
2.如果視頻格式已經(jīng)是avch264的了那么就需要看看是后臺(tái)原因還是原生那邊的原因了,一般來說應(yīng)該是后臺(tái)的問題鸳慈,ios目前獲取視頻的時(shí)候請求頭會(huì)帶一個(gè)與斷點(diǎn)續(xù)傳有關(guān)的信息饱溢,后臺(tái)需要對此進(jìn)行相應(yīng)的配置。而部分安卓手機(jī)也會(huì)用類似的方式請求視頻走芋,目前項(xiàng)目里的后臺(tái)同事將返回的狀態(tài)碼從200改成了206就ok了绩郎。
最后,轉(zhuǎn)載請注明出處http://www.reibang.com/p/8f39050aa607
本文參考文章
視頻播放--踩坑小計(jì)
h5 video 移動(dòng)端填坑記
移動(dòng)端實(shí)踐 - video