1. 程式人生 > >video 標籤沉浸式播放解決方案

video 標籤沉浸式播放解決方案

“沉浸播放式”這個概念是我從Android開發裡面的沉浸式引申過來的一個概念,沉浸式其實就是隱藏頁面頂部的status bar和底部的navigation bar之後呈現出來的頁面,一般使用者很容易把沉浸式狀態列和透明化狀態列混為一談,他們的區別如下:

沉浸式狀態列

透明化狀態列

那麼回到前端開發,讓我們看一下如何讓video標籤呈現這種沉浸式的播放效果,平常我們使用video標籤都是這樣的:

<div id="app">
 <video
   id="videos"
   playsinline="true"
   webkit-playsinline="true" /*IOS播放視訊會自動呼叫原生播放器全屏播放,這裡使用這個屬性讓IOS內播放視訊的時候使用inline模式,同時我們設定寬高等於螢幕寬高來實現IOS下的全屏播放*/
   x5-video-orientation="portraint"
   preload="auto"
   style="width: 100%;height: 100%"
 >
   <source src="//gw.alicdn.com/bao/uploaded/TB1YKBlb_ZRMeJjSsppXXXrEpXa.mp4" type="video/mp4">
 </video>
</div>

正常情況下我們要做豎版視訊,視訊的比例都是16:9,也就是高/寬約等於1.78,這裡用到的測試視訊也是16:9的,而且預設情況下video的object-fit屬性的值是contain,也就是保持長寬比,我們先看下不做處理在iphone6/7/8下的表現情況:

在iphone6/7/8下的表現情況

看起來比較完美,因為這幾款手機解析度都是16:9的,視訊維持螢幕大小完全沒有問題,接下來看一下解析度不是16:9的機型,比較典型的就是iphoneX,面向老闆開發的同學可能對適配這款機型頗有怨言:

iphoneX下的表現情況

有人會覺得奇怪為什麼我們設定了video的寬高都是百分百上下還漏出了兩個白條,這裡其實是object-fit這個屬性在作怪,既然預設的是contain,我們就改為fill吧,再看一下效果:

object-fit:fill

這樣看起來沒問題,但是你覺得產品小姐姐會這麼輕易放過你嗎?too navie,你看我們正常16:9的視訊在iphoneX這種18:9的螢幕上是有形變的,而且市面上這麼多解析度不同的裝置,如果要追求不同的手機上有最接近的使用者體驗這麼做肯定是不行的,有人可能會提到object-fit中的cover屬性,沒錯,這個屬性可以讓我們的視訊等比例縮放,如果寬高不匹配會對處理物件做裁剪操作,來我們看一下現在在微信裡面的效果:

微信裡的效果

其他效果都蠻好,你會發現右上角有個可惡的全屏,這個全屏按鈕是微信的x5核心自帶的,沒法去除,這個有很多人給騰訊x5開發團隊那邊提過issue,但是暫時沒有辦法處理,我後續會提到一個另闢蹊徑的方案,先回到這裡,點了這個全屏按鈕之後會進入微信的全屏播放模式,而且放完之後會出現一堆廣告列表,這都是我們不想看到了,其次如果我們的產品需求不單單是全屏播放,還想在視訊上面放一些互動按鈕之類的,這種方式就做不到,因為video是在最上一級的,但是兩種方式例外,一個是微信把你們的域名加入白名單,這種可以在Android手機的video上隨意放置dom元素,IOS本身沒有這個限制,另一種更為通用的方式是用微信x5核心的同層播放模式,這種模式有兩種好處:

  • 去除了右上角討厭的”全屏”按鈕

  • 真正實現了x5核心下的沉浸式播放,我們看到目前的實現在微信上還是帶有瀏覽器的titleBar的 在x5核心的環境下實現同層播放很簡單,只需要在video上新增這麼兩行屬性:

x5-video-player-type="h5"
x5-video-player-fullscreen="true"

再看一下這個時候的效果:

同層播放模式下的效果

確實是真正意義上的沉浸式播放,如果你的app裡面webview用的也是x5核心那麼這個頁面也能在app上達到同樣的效果,但是這種同層播放依然有無法解決的問題,首先這個全屏模式會重新計算寬高,觸發視口大小變化,也就是說使用者視覺上會有一個視口變化的過程,其次,同層播放模式雖然沒有了”全屏”按鈕,但是左上角的按鈕用於退出沉浸式全屏,右上角的按鈕點開是分享,分享的內容不可定製,固定位當前頁面的title+url的組合,如果你對頁面的定製化要求比較高的話,我這裡有一個備選的方案,那就是放棄同層播放模式,當然這個前提是你不需要在video頁面上做一些互動操作,或者說你的域名處於微信白名單下,當我們在非沉浸式下又想要打到等比例縮放視訊的效果,同時我們還要去除x5自帶的”全屏”按鈕,最好的方式就是動態去計算視訊的寬高,把視訊撐大,把”全屏”按鈕撐出瀏覽器頁面,這樣基本就能達到我們的目的了,這裡以16:9的標準為例:

this.$nextTick(() => {
     // 動態處理video標籤寬高適配
     const video = this.$refs.video
     const ratio = Math.fround(document.documentElement.clientHeight / document.documentElement.clientWidth)
     if (ratio >= 1.78) {
       // 豎屏
       video.height = document.documentElement.clientHeight + 100
       video.width = Math.floor(video.clientHeight * 0.572)
       const winW = document.documentElement.clientWidth
       video.style.left = (winW - video.width) / 2 + 'px'
     } else {
       // 寬屏
       video.width = document.documentElement.clientWidth + 100
       video.height = Math.floor(video.width * 1.78)
       const winH = document.documentElement.clientHeight
       video.style.top = (winH - video.height) / 2 + 'px'
     }
   })

講解下思路,16:9的視訊也就是高寬比差不多是1.78,那麼大於這個比例的就是類似於iphoneX的長螢幕型別的手機,對於這種手機我們要做等比縮放適配的話就以手機的長為標準,先讓視訊的長度等於手機的長度,這裡我加上的100px可以理解為上下在加上50px,目的就是為了把視訊長度拉大,讓”全屏”按鈕消失在視線內,實際這個值可以自己嘗試修改,讓後寬就是此時高的1/78倍,然後使用絕對佈局去設定視訊的左邊距,就可以達到等比縮放的效果,同理可以理解處理寬屏手機的程式碼部分,當然,應該還有更完美的方案,可以在評論區留言探討~