最近做個移動端視頻需求,要求隱藏播放控件,並且可以自動播放而且隱藏播放控件(不太人性化),最后要有個定制的結束遮罩層用來人機交互。嘗試直接用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節點一樣操作視頻了,尤其是定制視頻交互控件的樣式,基本都可以滿足產品的各種無厘頭需求啦!最后獻上我的頁面

注意是有聲音的‘視頻’哦!
