012. vue 實現(xiàn)一個移動端橫向滑動視頻預(yù)覽組件(精靈圖)

前言
在互聯(lián)網(wǎng)發(fā)展飛速的今天,誕生了許多在線觀看視頻的需求。由于視頻往往較長,僅靠一個封面是無法較好地反映視頻內(nèi)容的,因此視頻預(yù)覽功能應(yīng)運而生。
在 PC 端,當鼠標放到進度條上時就會出現(xiàn)縮略圖來預(yù)覽這個時間點的截圖,現(xiàn)在很多視頻網(wǎng)站都有這個功能。但在移動端,當手指放到進度條上時,在預(yù)覽后視頻進度也會相應(yīng)跳轉(zhuǎn),這是我們不想看到的。為了解決這一問題,擬開發(fā)一移動端橫向滑動視頻預(yù)覽組件。
實現(xiàn)
1.? 縮略圖生成
對于不同長度的視頻,我們每隔一定時間,切出一幀作為視頻縮略圖。一般每隔 30s 截取一張,對于中長視頻往往需要截取50張以上。大量的縮略圖不利于存儲、傳輸,在網(wǎng)絡(luò)較差的情況下,加載需要較長時間,容易影響用戶體驗。故選擇使用精靈圖技術(shù),即將多張縮略圖合并在一張圖片中的技術(shù)。
使用 ffmpeg 可以快速生成視頻縮略圖,在本文中生成的為 5x6 精靈圖。對于示例中的 2G大小的 1080P 視頻,切片后的單張縮略圖僅有 600K 大小。

2. 縮略圖展示
對于精靈圖在網(wǎng)頁中的顯示,我們可以使用 background 屬性控制圖片的某一分片如何展示。
首先,我們需要一個放置所有縮略圖的橫向滾動父盒子,里面先放 3 個顯示縮略圖的子盒子:
當我們以?background-image 將圖片引入時,我們會發(fā)現(xiàn)背景圖片的第一片并沒有貼合我們的盒子。這是因為瀏覽器還是以圖片原始尺寸大小顯示的,只不過多余部分被裁剪了而已。

因此我們需要將圖片調(diào)整為寬是子盒子的 5 倍,高是子盒子的 6 倍,使用?background-size 的百分比控制。
這樣以來,我們的背景圖片大小就與子盒子有了比例關(guān)系,第一片也就正常顯示了。

對于其它分片,僅需參照原點進行偏移即可,剛好?background-position 就提供了這個功能。
給定背景圖像位置的百分比偏移量是相對于容器的。值 0% 表示背景圖像的左(或上)邊界與容器的相應(yīng)左(或上)邊界對齊,或者說圖像的 0% 標記將位于容器的 0% 標記上。值為 100% 表示背景圖像的?右(或?下)邊界與容器的?右(或?下)邊界對齊,或者說圖像的 100% 標記將位于容器的 100% 標記上。因此 50% 的值表示水平或垂直居中背景圖像,因為圖像的 50% 將位于容器的 50% 標記處。類似的,
background-position: 25% 75%
?表示圖像上的左側(cè) 25% 和頂部 75% 的位置將放置在距容器左側(cè) 25% 和距容器頂部 75% 的容器位置。基本上發(fā)生的情況是從相應(yīng)的容器尺寸中減去背景圖像尺寸,然后將結(jié)果值的百分比用作從左(或頂部)邊界的直接偏移量。
(container width - image width) * (position x%) = (x offset value) (container height - image height) * (position y%) = (y offset value)
根據(jù)MDN 中的解釋,我們可以計算出第 ?i 行 j 列的分片偏移值:
其中,m 與 n 分別為行列分片數(shù)量,在本文中,m=5, n=6。
任意選取第 3 行 4 列的分片,在第二個子盒子里展示:
對比原圖,可以發(fā)現(xiàn)第?3 行 4 列的分片成功顯示了出來。

3. 動態(tài)渲染
搞清楚了圖片基本顯示邏輯后,我們就可以在 vue 中實現(xiàn)其完整功能了。關(guān)鍵功能:監(jiān)聽當前顯示分片索引并顯示、前一張縮略圖即將顯示結(jié)束,提前拉取下一張渲染。
這兩個功能,都使用?IntersectionObserver 來實現(xiàn)。對于第一個功能,監(jiān)聽所有縮略圖,判斷是否出現(xiàn)在 1% 的可視范圍內(nèi),動態(tài)修改當前索引。
對于動態(tài)加載的實現(xiàn),先計算出全部縮略圖的分片偏移值、索引等信息,構(gòu)造二維數(shù)組。組件初始僅渲染該數(shù)組第一張縮略圖內(nèi)的分片,監(jiān)聽到即將滾動到結(jié)尾時,推出剩余數(shù)組的第一張分片到渲染數(shù)組,利用 vue 的響應(yīng)式數(shù)據(jù)綁定進行動態(tài)渲染。
監(jiān)聽加載邏輯如下:
組件 template內(nèi)容:
最終效果如圖所示:

延伸閱讀
background - CSS:層疊樣式表 | MDN:https://developer.mozilla.org/zh-CN/docs/Web/CSS/background
IntersectionObserver - Web API 接口參考 | MDN:https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver
【重點】CSS之精靈圖 - 知乎:https://zhuanlan.zhihu.com/p/436792962