react中使用canvas播放视频

最近做个移动端视频需求,要求隐藏播放控件,并且可以自动播放而且隐藏播放控件(不太人性化),最后要有个定制的结束遮罩层用来人机交互。尝试直接用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={{ '100%',height: 'auto'}} id={'scrollBox'}>
      <canvas width='1280' height='720' ref={node => this.canvas = node} style={{ '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