如何制作一个自定义进度条,使其在YouTube嵌入式视频播放时平滑动画?

3

YouTube视频的加载进度在不断变化的过程中,难以产生平滑的动画进度条。即使是YouTube内置的进度条也不够流畅。但我认为必须有一种方法可以解决这个问题。

我正在使用自定义控件来嵌入YouTube视频,但我的进度条移动方式不流畅,而是跳跃性的。以下是代码:

vidClock = setInterval(function() {
    if (state == 1) {
        var time = player.getCurrentTime();
        var percent = (time / duration) * 100;
        $seekSlider.css({
            'width' : percent + '%'
        });
    }
}, 100);

这个变量的起源并没有全部显示,但它们所代表的应该是显而易见的。我该如何使这个进度条平滑移动?
我尝试为元素添加CSS过渡效果,并尝试设置更小的间隔,例如10、20和30(在建议后,尝试使用JQuery动画)。
例如,使用下面答案中建议的$.animate并不平滑:http://jsfiddle.net/e11oy0eu/290/

1
一定有办法获得平滑的进度条动画。我注意到即使是YouTube的进度条也不够平滑,但似乎一定有方法可以做到。 - user5536767
4个回答

2
我选择了一种不同的方法来解决你的问题,首先我添加了Velocity.js到项目中,因为正如Alon在他的回答中所说,它可以提供更好的动画效果。然后,我没有设置计时器并根据播放器当前时间改变进度条大小,而是创建了一个总是动画到100%的进度条,然后使用一些事件来停止进度条当视频播放停止(由用户或缓冲停止)。虽然这种策略有其缺点,但它可以提供更平滑的动画效果。
此外,为了获得更加流畅的动画效果,我将
的位置更改为absolute,并使用transform:translateX属性移动它。(我不确定这个更改有多大的效果,也许根本没有效果)。
.progress-container {
  width: 640px;
  height: 30px;
  background-color: #efefef;
  position: relative;
  overflow: hidden;
}

.progress {
  width: 100%;
  height: 100%;
  background-color: green;
  position: absolute;
  left: -100%;
  top: 0;
}

在这些更改后,handleState函数看起来像这样:
function handleState(state) {
  var $seekSlider = $('.progress');
  var $seekContainer = $('.progress-container');

  if (state == 1) { // when player starts playing
    duration = player.getDuration();
    currentTime = player.getCurrentTime();
    currentLocation = ((currentTime/duration) * 100).toFixed(4);

    $seekSlider
      .velocity('stop')
      .velocity({
        'translateX': currentLocation + '%'
      }, {duration: 0})
      .velocity({
        'translateX': '100%'
      }, {
        duration: Math.floor((duration-currentTime) * 1000),
        easing: 'linear'
      });
  }

  if (state == 2 || state == 3 || state == 0) {
    $seekSlider.velocity('stop');

    if (state == 3) {
      duration = player.getDuration();
      currentTime = player.getCurrentTime();
      currentLocation = ((currentTime/duration) * 100).toFixed(4);

      $seekSlider.velocity({
        'translateX': currentLocation + '%'
      }, {duration: 0});
    }

    if (state == 0) {
        $seekSlider.velocity({
        'translateX': '100%'
      }, {duration: 0});
    }
  }
}

你可以在这个JSFiddle链接中查看工作结果和完整代码,并带有一些注释。此外,我创建了一个gist链接,展示了你的脚本和我的脚本之间的差异。请注意保留HTML标签。

抱歉我的语法不好;) - Alireza Ahmadi

2
粗糙的进度条不仅是由于getCurrentTime函数造成,还由于您调整进度条大小的方式。即使在以百分比设置CSS width时,它也始终呈现为整个像素。您可以使用transform,它将呈现“半”像素。
接下来,为了克服getCurrentTime不在每次调用时更新的限制,您可以将其值保存在变量中,并使用计时器间隔手动增加它:
function handleState(state) {
  var $seekSlider = $('.progress');
  var $seekContainer = $('.progress-container');
  if (state == 1) {
    duration = player.getDuration();
    var prevTime = 0;
    var elapsed = 0;
    vidClock = setInterval(function() {
      elapsed += 0.05; // Increase with timer interval
      if ((state == 1) && (seeking == false)) {
        var time = player.getCurrentTime();
        if (time != prevTime) {
          elapsed = time; // Update if getCurrentTime was changed
          prevTime = time;
        }
        var percent = (elapsed / duration);
        $seekSlider.css({
          'transform': 'scaleX(' + percent + ')'
        });
      }
    }, 50);
  } else {
    clearInterval(vidClock);
  }
}

查看更新后的小样(样例),请点击此处

2
您可以使用 .animate() 函数:
vidClock = setInterval(function() {
    if (state == 1) {
        var time = player.getCurrentTime();
        var percent = (time / duration) * 100;
        $seekSlider.animate({
            'width' : percent + '%'
        },500);
    }
}, 500);

或者使用 CSS 动画:

CSS 代码:

.progress {
    width: 0%;
    height: 100%;
    background-color: green;
    transition: all 0.5s linear;
}

JS:

vidClock = setInterval(function() {
    if (state == 1) {
        var time = player.getCurrentTime();
        var percent = (time / duration) * 100;
        $seekSlider.css({
            'width' : percent + '%'
        });
    }
}, 500);

好主意,但不幸的是结果只稍微好一点,当我尝试使用5、10、30、100或150的间隔时仍然非常跳跃。 - user5536767
你有示例可以看看发生了什么吗? - cansyrup756
我会创建一个 JSFiddle。 - user5536767
getCurrentTime() 似乎只会每 ~500ms 更新一次,尝试使用该间隔。 - cansyrup756
当我对JS Fiddle进行了那个修改时,我没有看到太多平滑度的改善。http://jsfiddle.net/e11oy0eu/290/ - 仍然是非常粗糙的动画。 - user5536767
显示剩余4条评论

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接