VideoJsCustomization
VideoJsCustomization copied to clipboard
HTML5 视频播放器 自定制: React + video.js 详细讲解
在 React 项目中,使用 video.js 进行 HTML5 视频播放器的自定制
讲解稿
0-Intro
案例目的:
在 React 项目中使用 video.js,实现 HTML5 视频播放器的自定制。
关于 video.js:
引用官方的自我介绍:
video.js is a free and open source HTML5 video player.
这是个免费且开源的 HTML5 视频播放器。
1-着手开发
video.js 使用了 Grunt 作为构建工具。所以,在开始写代码之前,请确保开发环境里已经装有 Node 和 Grunt
安装 Grunt:
npm install -g grunt-cli
2-创建一个 React 项目
create-react-app myVideoPlayer
然后删去对我们没用的代码
3-React 项目中引入 video.js
本节,我们将在 React 项目中引入 video.js ,为单调的页面上添加一个 HTML5 视频播放器。
安装 video.js
npm install --save-dev video.js
项目中引入 video.js
对于如何在 React 项目中使用 video.js ,官方文档就这一篇: video.js and ReactJS integration
我们参考文档中的基本方法,主要思路就是利用 React 组件的生命周期函数:
- 在
componentDidMount阶段实例化一个 video.js 播放器 - 在
componentWillUnmount阶段将其销毁
在我们的项目中,新建文件夹 src/lib/VideoPlayer,在其中新建组件 VideoPlayer.js:
特别注意,需要加入对 css 文件的引用
VideoPlayer.js
import React from 'React'
import videojs from 'video.js'
import 'video.js/dist/video-js.css'
export default class VideoPlayer extends React.Component {
componentDidMount () {
// instantiate video.js
this.player = videojs(this.videoNode, this.props, function onPlayerReady () {
console.log('onPlayerReady', this)
})
}
// destroy player on unmount
componentWillUnmount () {
if (this.player) {
this.player.dispose()
}
}
// wrap the player in a div with a `data-vjs-player` attribute
// so videojs won't create additional wrapper in the DOM
// see https://github.com/videojs/ video.js /pull/3856
render () {
return (
<div data-vjs-player>
<video ref={node => this.videoNode = node} className='video-js' />
</div>
)
}
}
然后新建课程组件,它将引用 VideoPlayer 组件:
根据 Dan Abramov的思想,组件拆分为展示性组件和容器组件(Presentational and Container Components)
src/containers/App.js
import React, { Component } from 'React'
import CourseContainer from './CourseContainer'
class App extends Component {
render () {
return (
<div className='app'>
<CourseContainer />
</div>
)
}
}
export default App
src/containers/CourseContainer.js
import React, { Component } from 'React'
import Course from '../components/Course'
class CourseContainer extends Component {
render () {
// VideoJsOptions for this Course
const CourseVideoJsOptions = {
autoplay: true,
controls: true,
sources: [{
src: 'http://vjs.zencdn.net/v/oceans.mp4',
type: 'video/mp4'
}]
}
return (
<Course videoJsOptions={CourseVideoJsOptions} />
)
}
}
export default CourseContainer
src/components/Course.js
import React, { Component } from 'React'
import VideoPlayer from '../lib/VideoPlayer/VideoPlayer'
class Course extends Component {
render () {
return (
<div className='course-container'>
<h2>CourseDemo</h2>
<VideoPlayer {...this.props.videoJsOptions} />
</div>
)
}
}
export default Course
至此,在课程页面上就已经有一个播放器了。我们在 React 项目中成功引入了 video.js 。
很容易发现,页面加载完成后,播放器会自动播放视频。能否禁止这个默认行为呢?
下一节我们就看如何对播放器的功能进行控制和扩展。
4-用 options 控制功能
本节,我们用 options 实现对基本功能的控制。
video.js 中,可以通过 options 对播放器实例进行控制,如循环播放、静音、以及宽高样式等方面。
上面案例代码中的 CourseVideoJsOptions 就是一个例子。定义一个 options 对象,将其作为参数传入 VideoPlayer 组件中:
src/components/Course.js
... ...
<VideoPlayer {...this.props.videoJsOptions} />
... ...
案例代码中的 options 对象如下:
const CourseVideoJsOptions = {
autoplay: true,
controls: true,
sources: [{
src: 'http://vjs.zencdn.net/v/oceans.mp4',
type: 'video/mp4'
}]
}
其中有三个 key,对照 options 文档,不难知道
- autoplay 是否自动播放
- controls 是否显示控制条
- sources 规定视频源
通过 options,我们可以对功能进行控制与添加:
- playbackRates:倍速播放
- poster: 视频播放前显示的图片
- volumePanel:音量条
- fluid: 播放器自动充满容器
const CourseVideoJsOptions = {
autoplay: false,
controls: true,
sources: [{
src: 'http://vjs.zencdn.net/v/oceans.mp4',
type: 'video/mp4'
}, {
src: 'http://vjs.zencdn.net/v/oceans.webm',
type: 'video/webm'
}],
poster: 'http://videojs.com/img/logo.png',
fluid: 'true', // put the player in the VideoPlayerWrap box
'playbackRates': [0.75, 1, 1.5, 2],
controlBar: {
volumePanel: {
inline: false // 将音量控制条垂直
}
}
}
注意:这里 sources 对应的值是一个视频源对象数组。数组中每个 src 都是同一个视频,但格式各异。
这样可以解决不同浏览器之间的兼容性问题:Video.js 会检测当前浏览器所支持的视频格式,然后在数组中选择合适的视频源进行播放。
src/components/Course.js
import React, { Component } from 'React'
import VideoPlayer from '../lib/VideoPlayer/VideoPlayer'
import styled from 'styled-components'
const VideoPlayerWrap = styled.div`
margin: 10px;
padding: 10px;
border: 2px solid green;
`
class Course extends Component {
render () {
return (
<div className='course-container'>
<h2>CourseDemo</h2>
<VideoPlayerWrap>
<VideoPlayer {...this.props.videoJsOptions} />
</VideoPlayerWrap>
</div>
)
}
}
export default Course
注:这里使用了 styled-component。
在播放器外套了一层 VideoPlayerWrap(其实就是 div ),这么做的好处在于:
- 由于 VideoPlayer options 中打开了
fluid,播放器可以自适应 VideoPlayerWrap 容器。如此,options 就可以专注于对功能进行控制。 - VideoPlayerWrap 的样式代码,同时也规定了播放器的样式。将样式代码集中写到展示性组件中,也符合 Dan Abramov 的思想
本节,我们用 video.js 的 options 机制,实现了播放器的倍速播放、添加 poster、样式控制等功能。
以上都是对现有功能进行控制。下一节,我们来看看如何按照我们的想法,对播放器的功能进行扩展。
5-写插件(Plugin)扩展功能
本节,我们的目的是,扩展空格键控制播放/暂停的功能。
video.js 的默认动作是,仅仅在 control bar 的播放键被鼠标选中时,才能用空格/回车键控制播放/暂停。不太方便。 我们要将其改进为:点开视频后,就可以通过空格键控制视频的播放/暂停。
引入插件
我们可以通过写自己的插件来实现额外的功能。参考这篇文档,尝试如下:
VideoPlayer.js
··· ···
render () {
// 写插件:当监听到播放器实例的播放(play)事件,就输出一条语句
function examplePlugin(options) {
this.on('play', function(e) {
console.log('playback has started!');
});
};
// 注册该插件
videojs.registerPlugin('examplePlugin', examplePlugin)
return (
··· ···
目前插件已经存在,可以根据需要打开或关闭它
下面尝试使用
CourseContainer.js
··· ···
const CourseVideoJsOptions = {
autoplay: false,
controls: true,
... ...
// 使用该插件
plugins: {
setStateandFocusPlugin: true
}
}
... ...
完成以上步骤后,再次点开视频,发现控制台输出了 playback has started! ,说明插件应用成功。
关于代码中的事件监听,参考文档 Event Target
设置播放器实例的状态
在插件代码中加一条 console 语句如下。
如此,在控制台中,就可以在点开视频时看到,这句代码输出了该播放器的实例对象
VideoPlayer.js
··· ···
function examplePlugin(options) {
this.on('play', function(e) {
console.log(this)
console.log('playback has started!')
});
};
... ...
仔细查看该对象的属性,发现有 setState 和 state 两条。
据此,我们尝试根据播放器的播放状态来设置 state 值
注意,这和 React 组件的 state 是两回事。
VideoPlayer.js
··· ···
this.on('play', function (e) {
console.log(this);
console.log('playback has started!')
this.setState({
state: 'playing'
})
console.log(this.state.state)
})
this.on('pause', function (e) {
console.log('playback has paused')
this.setState({
state: 'pause'
})
console.log(this.state.state)
})
... ...
此时,再让视频播放/暂停,都会看到控制台输出的状态,说明设置成功。
初步改进空格键的功能
空格键的默认动作是:
- 当鼠标选中 control bar 的播放键时,空格键可以切换播放/暂停;
- 当鼠标选中全屏键时,空格键可以切换全屏;
- 当鼠标选中静音键时,空格键可以切换静音;
- 当鼠标什么也没选中时,空格键无法控制播放器的任何功能。
这样既麻烦又不实用,因为只有“播放/暂停”功能才是使用频率最高的功能。让空格键在任何情况下都能直接控制暂停功能,可以明显提升用户体验。
接下来,我们需要监听“按下空格键”这个事件。这个需求可以分为两步:
- 监听键盘事件
- 判断是否为空格键
对于前者,我们可以使用 onKeyDown 事件,它会在用户按下一个键盘按键时发生。
对于后者,涉及到 keyCode/键码-文档链接待补充的知识。具体到这个案例,空格键的键码是32。
推荐这个网站,它可以很方便地查询键盘各个按键的键码,十分好用。
通过 onKeyDown 事件的文档可以看到,