最近做個移動端視頻需求,要求隱藏播放控件,並且可以自動播放而且隱藏播放控件(不太人性化),最后要有個定制的結束遮罩層用來人機交互。嘗試直接用video標簽做,但是各種坑啊,video永遠是在頁面的最頂層,所以播放控件的自定義化就涼涼了,怎么辦呢?受以前做的一個利用canvas做視頻直播的項目啟發,嘗試下canvas做視頻播放,於是我抱着試一試的心態去查閱了相關資料,尼瑪,還真的可以,而且原理很簡單!
首先要解決在react中操作canvas的問題,眾所周知,react和vue都是生成的虛擬dom,直接通過dom的API操作canvas是不現實的。npm上的一些庫也是繁瑣的像XX。。。我寫了一個方法,在react的componentDidMount中利用react的ref把canvas直接傳給這個方法,拿到了頁面上的canvas,只要這個頁面不卸載,我就可以為所欲為啦!直接上代碼:
import React, { Component } from 'react'; import './App.css'; import {draw} from './canvas' class App extends Component { componentDidMount() { if (this.canvas) { draw(this.canvas) } } render() { return <div style={{width: '100%',height: 'auto'}} id={'scrollBox'}> <canvas width='1280' height='720' ref={node => this.canvas = node} style={{width: '100%',height: 'auto'}}></canvas> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> <p>我是測試我是測試</p> </div>; } } export default App;
通過ref函數把canvas賦值給this.canvas,在componentDidMount鈎子中傳給canvas腳本文件繪制(注意,由狀態動態生成的canvas可能拿不到這個dom,建議放到componentDidUpdate鈎子中,不熟悉react生命周期的同學自行查閱官方文檔),於是這個時候,我拿出了我的終極大殺器——canvas.js.好了,不吹牛皮,其實它就是一個非常簡單的腳本,看看它的代碼:
export const draw = (canvas) => { if (canvas) { //獲取canvas上下文 let ctx = canvas.getContext('2d'); //創建video標簽,並且設置相關屬性 let video = document.createElement('video'); video.preload = true; video.autoplay = true; video.src='https://pic.ibaotu.com/00/92/91/90f888piCjkw.mp4'; //document.body.appendChild(video); //監聽video的play事件,一旦開始,就把video逐幀繪制到canvas上 video.addEventListener('play',() => { let play = () => { ctx.drawImage(video,0,0); requestAnimationFrame(play); }; play(); },false) //暫停/播放視頻 canvas.addEventListener('click',() => { if (!video.paused) { video.pause(); } else { video.play(); } },false); } }
大概的思路就是我首先在內存中創建一個video標簽並設置好相關屬性,之后監聽video的play事件,一旦開始播放,我就會通過requestAnimationFrame把video逐幀繪制到canvas上。由於真的有個video在播放視頻,所以你會聽到聲音,但是,我並沒有把它放到頁面上,所以你看到的不是視頻,而是一個沒有聲音的canvas!嘿嘿嘿O.o
視頻這樣子處理,雖然依舊不能跨過谷歌和蘋果爸爸對視頻自動播放的限制,但是可以像操作普通div節點一樣操作視頻了,尤其是定制視頻交互控件的樣式,基本都可以滿足產品的各種無厘頭需求啦!最后獻上我的頁面
注意是有聲音的‘視頻’哦!