标签中。代码如下
401 |
402 | **VideoPlayer.js**
403 | ```
404 | ··· ···
405 | videojs.registerPlugin('setStateandFocusPlugin', setStateandFocusPlugin)
406 | // videojs.registerPlugin('handleKeyPress', handleKeyPress)
407 |
408 | return (
409 |
412 |
417 | )
418 | }
419 | }
420 | ```
421 |
422 | 由于 JS 的[事件冒泡-文档链接待补充]()机制,onKeyDown 事件是可以成功捕获的。
423 |
424 | 事实上,如果在目前这个 div 标签的外层再套一层 div ,外层的 div 也同样能够捕获 onKeyDown 事件,有兴趣的可以试一下。
425 |
426 | 接下来写监听到 onKeyDown 事件后调用的函数:
427 |
428 | * 首先,我们需要判断是否为空格键。
429 | * 如果是,我们需要禁止原来默认的动作。
430 | * 然后,利用之前设置的视频播放状态,进行相应的操作:
431 | * 如果视频正在播放中,则暂停视频
432 | * 如果视频正在暂停中,则继续播放视频
433 |
434 | **VideoPlayer.js**
435 | ```
436 | ··· ···
437 | componentWillUnmount () {
438 | if (this.player) {
439 | this.player.dispose()
440 | }
441 | }
442 |
443 | handleSpaceKeyDown = (event) => {
444 | // 判断是否为空格键
445 | if (event.which === 32) {
446 | event.preventDefault()
447 | if (this.player) {
448 | // 根据播放状态的不同,进行相应的操作
449 | switch (this.player.state.state) {
450 | case 'playing':
451 | this.player.pause()
452 | break
453 | case 'pause':
454 | this.player.play()
455 | break
456 | default: return
457 | }
458 | } else {
459 | console.log('error')
460 | }
461 | }
462 | }
463 | ... ...
464 | ```
465 |
466 | 至此,我们完成了初步的改进。但目前扔有一些问题:
467 | * 点击视频播放后,必须再点一下视频,才能用空格键控制暂停/播放;
468 | * 如果在播放时,鼠标点一下页面上的其他地方,空格键又失效了。
469 |
470 | 下一步来解决这些问题。
471 |
472 | #### 改进焦点管理
473 |
474 | 元素获得焦点的方式有页面加载、用户输入(通常是通过 Tab 按键)和在代码中调用 `focus()` 方法。相应的文档获得了焦点,用户才能与页面交互。
475 |
476 | 于是,我们是思路是:当视频播放时,调用 `focus()` 方法,使得播放器获得焦点。
477 |
478 | 如何获取播放器的 DOM 元素?可以使用 React 的 ref。
479 | 参考 [Refs and the DOM](https:// React js.org/docs/refs-and-the-dom.html)
480 |
481 | 如何在插件代码中获取 React 组件?可以从它的外部传 `this` 进去。
482 |
483 | 尝试改进代码:
484 |
485 | **VideoPlayer.js**
486 | ```
487 | ··· ···
488 | render () {
489 | // write a plugin
490 | var that = this
491 | const setStateandFocusPlugin = function (options) {
492 | this.on('play', function (e) {
493 | console.log('playback has started!')
494 |
495 | // 控制台输出结果表明成功获取VideoPlayer组件
496 | console.log(that)
497 |
498 | this.setState({
499 | state: 'playing'
500 | })
501 | // 控制焦点
502 | that.refs.videoPlayerRef.focus()
503 | })
504 | ... ...
505 | return (
506 |
510 |
515 | )
516 | }
517 | }
518 | ```
519 |
520 | 现在再试用播放器,可以发现第一个问题已经解决了。点开视频后,直接按空格键,视频暂停。
521 |
522 | 第二个问题依然存在。这是因为 `this.on('play', cb)` 这个监听事件不是持续的。视频播放的过程中,再点击页面的其他地方,播放器会市区焦点。
523 |
524 | 有没有更好的方法? video.js 的 github issue 里,官方人员提及 video.js 支持全部原生 HTML5 media elements events, 仔细查阅 [W3C Recommendation 文档 media event summary部分](https://www.w3.org/TR/ HTML5 /embedded-content-0.html#mediaevents),以及官方人员的 [events文档](http://docs.videojs.com/docs/api/player.html#events),发现这一条:
525 |
526 | >**timeupdate**
527 | >
528 | >Fired when the current playback position has changed * During playback this is fired every >15-250 milliseconds, depending on the playback technology in use.
529 | >
530 | >Defined in https://github.com/videojs/ video.js /blob/master/src/js/player.js line number: 2792
531 |
532 |
533 | 只要在播放,就会持续监听到该事件。十分适合用来解决我们的问题。有了它,`this.on('play', cb)`的回调中也不需要进行焦点控制了。
534 |
535 | 根据该插件的功能,将其命名为 `setStateandFocusPlugin`,完整代码如下
536 |
537 | **VideoPlayer.js**
538 | ```
539 | ··· ···
540 | const setStateandFocusPlugin = function (options) {
541 | this.on('play', function (e) {
542 | console.log('playback has started!')
543 | console.log(that)
544 | this.setState({
545 | state: 'playing'
546 | })
547 | })
548 |
549 | this.on('pause', function (e) {
550 | console.log('playback has paused')
551 | this.setState({
552 | state: 'pause'
553 | })
554 | })
555 |
556 | this.on('timeupdate', function(e){
557 | that.refs.videoPlayerRef.focus()
558 | })
559 | }
560 | ... ...
561 | ```
562 |
563 | 注意,注册以及使用插件的代码中也需要同步改名。
564 |
565 | 现在再来尝试,发现第二个问题也解决了。
566 |
567 | 目前的代码可以实现:
568 | * 当视频播放的过程中,不论鼠标点哪里,都让焦点保持在播放器,以便通过空格键控制;
569 | * 看视频时也可能需要暂停下来做别的事情,那么当视频处于暂停状态,就可以通过鼠标点击等行为切换焦点。
570 |
571 |
572 | 空格键控制播放/暂停的功能就比较完善了。
573 |
574 | #### 总结
575 |
576 | 这一小节,我们实现了一个 video.js 的插件(涉及到插件的注册,使用等),通过它监听播放器实例的事件,在不同的事件被触发时,进行相应的操作:
577 | * 当监听到播放(`play`)事件的触发,设置播放器实例状态为 `playing`
578 | * 当监听到暂停(`pause`)事件的触发,设置播放器实例状态为 `pause`
579 | * 当监听到 `timeupdate` 事件的触发,让播放器组件获得焦点,涉及到
580 | * `focus()` 方法
581 | * `ref`
582 |
583 | 然后,监听键盘事件,当监听到用户按下空格键时,禁止原来的默认动作,再根据播放器实例此时的状态,进行相应的操作
584 | * 若正在播放中,则暂停之
585 | * 若视频被暂停,则播放之
586 |
587 | 涉及到:
588 | * `event.preventDefault()`
589 | * `onKeyDown`
590 | * 事件冒泡
591 | * 键码
592 |
593 |
594 |
595 | ### 6-实现样式的自定制
596 |
597 | 以上内容都聚焦于功能。本节,对播放器的外观进行修改,创造自己的播放器皮肤文件。
598 |
599 | 官方的 [Creating a Skin](http://docs.videojs.com/tutorial-skins.html) 文档中推荐的方法是直接覆盖掉原有的默认皮肤。
600 |
601 | #### 为播放器增加自定制的 `className`
602 |
603 | 文档中的示例代码为`