最近做个移动端视频需求,要求隐藏播放控件,并且可以自动播放而且隐藏播放控件(不太人性化),最后要有个定制的结束遮罩层用来人机交互。尝试直接用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节点一样操作视频了,尤其是定制视频交互控件的样式,基本都可以满足产品的各种无厘头需求啦!最后献上我的页面
注意是有声音的‘视频’哦!
原文地址:https://www.cnblogs.com/zhangbob/p/10039440.html