[Video.js]隐藏和显示视频播放器控件

10,582 阅读5分钟

原文链接:Hiding and Showing Video Player Controls

上周我决定解决一些围绕控制栏的悬而未决的问题,然后进入相关播放器更新的流程。我现在很幸运地有了一些时间,并且我会写一些关于它的更新。

播放器控制栏的预期行为之一是,当用户在观看视频时处于非活动状态时,它会在几秒钟后淡出。以前,我们通过video.js实现这一点的方式是通过一些CSS技巧。 当用户的鼠标移出视频播放器区域时,控制栏将被赋予名称为vjs-fade-out的class。这个class延迟了2秒后有一个转换动效。

.vjs-fade-out {
  display: block;
  visibility: hidden;
  opacity: 0;

  -webkit-transition: visibility 1.5s, opacity 1.5s;
     -moz-transition: visibility 1.5s, opacity 1.5s;
      -ms-transition: visibility 1.5s, opacity 1.5s;
       -o-transition: visibility 1.5s, opacity 1.5s;
          transition: visibility 1.5s, opacity 1.5s;

  /* 等一会儿,然后淡出控制栏 */
  -webkit-transition-delay: 2s;
     -moz-transition-delay: 2s;
      -ms-transition-delay: 2s;
       -o-transition-delay: 2s;
          transition-delay: 2s;
}

当用户的鼠标移回播放器时,该class将被删除,取消所有延迟淡出动效。这提供了一个简单的例子来达成你期望的控件淡出工作效果,只需要几行javascript来添加/删除class。

player.on('mouseout', function(){ 
  controlBar.addClass('vjs-fade-out'); 
});

player.on('mouseover', function(){ 
  controlBar.removeClass('vjs-fade-out'); 
});

虽然有一些缺点,但有仍必要摆脱这种方法。

  • 控制栏在全屏模式下不会淡出,因为鼠标有可能永远不会移出播放器区域。
  • 移动设备上没有鼠标,因此需要不同的事件和交互来显示/隐藏控件。

除了这些问题之外,我们希望它可以让任何播放器组件或插件hook到隐藏控件的同一个触发器中。像社交分享图标这样的组件应该随控制栏一起淡出。

用户状态

首先要添加的东西之一是播放器的userActive属性,可以是truefalse。这样做是将控件抽象为我们实际关心的内容,即用户目前是与播放器互动还是被动地观看视频。这也使控制栏不再跟踪用户活动本身,并且允许其他组件通过播放器级别的状态更容易地与控制栏保持一致。

该属性的调用是player.userActive(),并会返回truefalse。当这个值被改变时,它会触发播放器上的事件。

player.userActive(true)
    // -> 'useractive'事件被触发
player.userActive(false)
    // -> 'userinactive'事件被触发

播放器元素还添加了vjs-user-activevjs-user-inactive的CSS类名。类名实际上才是用来隐藏和显示控制栏的内容的。

.vjs-default-skin.vjs-user-inactive .vjs-control-bar {
  display: block;
  visibility: hidden;
  opacity: 0;

  -webkit-transition: visibility 1.5s, opacity 1.5s;
     -moz-transition: visibility 1.5s, opacity 1.5s;
      -ms-transition: visibility 1.5s, opacity 1.5s;
       -o-transition: visibility 1.5s, opacity 1.5s;
          transition: visibility 1.5s, opacity 1.5s;
}

2秒延迟已从CSS中删除,而是将内置到通过JavaScript timeout将userActive状态设置为false的过程中。只要播放器发生鼠标事件,该timeout就会重置。 例如:

var resetDelay, inactivityTimeout;

resetDelay = function(){
    clearTimeout(inactivityTimeout);
    inactivityTimeout = setTimeout(function(){
        player.userActive(false);
    }, 2000);
};

player.on('mousemove', function(){
    resetDelay();
})

mousemove事件在鼠标移动时会非常迅速地被调用,并且我们希望在此操作期间尽可能少地阻塞播放器进程,所以我们使用 John Resig 编写的一种技术。

而不是重置每个mousemove的timeout,而是通过mousemove事件来设置一个变量,该变量可以通过受控的JavaScript时间间隔来获取。

var userActivity, activityCheck;

player.on('mousemove', function(){
    userActivity = true;
});

activityCheck = setInterval(function() {

  // 检查鼠标是否被移动
  if (userActivity) {

    // 重置活动跟踪器
    userActivity = false;

    // 如果用户状态处于非活动状态,请将状态设置为活动状态
    if (player.userActive() === false) {
      player.userActive(true);
    }

    // 清除任何现有的不活动超时以启动计时器
    clearTimeout(inactivityTimeout);

    // 在X秒内,如果没有更多的活动发生,用户将被视为不活动
    inactivityTimeout = setTimeout(function() {
      // 防止在activityCheck循环拾取下一个用户活动之前可以触发非活动超时的情况。
      if (!userActivity) {
        this.userActive(false);
      }
    }, 2000);
  }
}, 250);

这可能有很多需要遵循的内容,并且与现在播放器中的实际内容相比略微简单一些,但本质上它允许我们在鼠标移动时从浏览器中获取一些处理权重。

全屏时隐藏控制栏

由于新的userActive状态和延迟的javascript timeout,控件不再需要鼠标移动到播放器区域外面才会隐藏,现在可以以全屏模式隐藏,就像播放器进入游戏时一样。这也意味着我们现在可以像使用控件一样隐藏鼠标光标,以便在全屏观看时不会让鼠标出现在播放器上。

.vjs-fullscreen.vjs-user-inactive {
  cursor: none;
}

在触摸设备上隐藏控制栏

触摸设备上的预期行为与桌面浏览器有所不同。没有mousemove事件可帮助确定用户是处于活动状态还是非活动状态,因此通常会在控件淡出之前添加较长的延迟时间。 此外,虽然在桌面浏览器中点击视频本身通常会在播放和暂停之间切换,但点击移动设备上的视频只会切换控件的可见性。

幸运的是,我们围绕userActive建立的框架使得这个最后的部分很容易设置。

video.on('tap', function(){
  if (player.userActive() === true) {
    player.userActive(false);
  } else {
    player.userActive(true);
  }
});

truefalse之间手动切换userActive将应用适当的类名,并触发显示和隐藏控件所需的事件,就像在移动设备上所期望的那样。

tap事件实际上是一个自定义事件,类似于你在jQuery mobile,Hammer.js和其他移动触摸库中发现的tap事件。每当touchstart事件触发并且相关的touchend事件在250毫秒内触发时,就会触发tap事件。如果touchend事件需要更长时间才能触发,或者两者之间发生touchmove事件,则不会将其视为轻敲。

结论

我希望这篇文章能够深入了解这些控件在Video.js中的工作方式,以及如何为Video.js构建自己的插件,从而模仿相同的交互。

干杯,

-heff