使用 JQueryUI 作为音频 Seek 控件,并在更改歌曲时将新滑块重新绑定到相同的 <audio> 控件

Using JQueryUI as an audio Seek control, and rebinding a new slider to the same <audio> control when a song is changed

感谢您查看我的问题。 Fiddle 是 HERE.

我正在尝试为页面上的许多歌曲实现音频播放器。这是使用 JQueryUI 滑块和 HTML5 音频,具有一个音频元素和多个滑块。

现在的问题是:

  1. 滑块不随音频动画。
  2. 滑块不定位到音频。
  3. 以前,当以上两个都起作用时,一旦您在歌曲中选择了一个位置,滑块将不再有动画效果。

我已经创建了点击新歌时 rebindSlider() 的功能。在这个函数中,发生了两件事:a) 创建了新的滑块,定义了 slide 和 stop 侦听器,以及 b) 新的滑块绑定到新歌曲的音频元素上的 timeupdate 事件。我觉得这应该是我所需要的,但是滑块没有绑定,并且当您尝试拖动滑块时可以看到 undefined 错误。

使用一个滑块和一个音频元素,我已经完成了 90%;但是,一旦我为滑块引入了多个 div,问题就开始出现了。

这是 rebindSlider 的代码:

function rebindSlider(sliderDiv) {
  var createSeek = function() {
    sliderDiv.slider({
      value: 0,
      step: 1,
      orientation: "horizontal",
      range: "min",
      max: audioPlayer.duration,
      animate: true,

      slide: function() {
        manualSeek = true;
      },

      stop: function(e, ui) {
        manualSeek = false;
        audioPlayer.currentTime = ui.value;
      }
    });
  };

  createSeek();

  $(audioPlayer).bind('timeupdate', function() {
    if (!manualSeek) {
      sliderDiv.slider('value', audioPlayer.currentTime);
    }
  });
} 

进一步的描述如下。

页面上有一个歌曲列表。每首歌曲都有一个包含 div,其中包含元数据的 <a>(fiddle 中没有),以及为音频搜索滑块指定的 div .页面上有一个音频元素,当您点击歌曲时会重新加载其源代码。

当点击一首歌曲时,我想销毁绑定到播放音频的滑块(如果需要),并将点击歌曲的新滑块绑定到音频播放器。

我最接近的是让滑块 1) 在歌曲播放时开始动画 2) 将滑块拖动到歌曲中的不同位置。但是,一旦滑块移动,它就不再具有动画效果。重构后,滑块不再工作,虽然我可以转到以前的提交来获取工作代码,但重构是如此激烈,以至于我更愿意展示当前的非工作代码,因为它更好地代表了我的想法想结束。

推理和附加信息。

我正在制作一个网络应用程序,为此我有一个音频播放器的概念,我宁愿自己构建也不愿修改我遇到的任何东西。话虽这么说,如果你知道我可以实施的东西,我很乐意提出建议。

这个想法听起来很简单,而且大部分都已经完成了,但是其中有一个非常关键的部分我遇到了麻烦,那就是设置滑块来制作动画,并寻找到所需的位置在音轨中,并能够在单击歌曲时将新滑块重新绑定到音频。

需要进行一些更改才能使滑块正常工作。我将分别介绍它们,以便它们适用。

滑块最大值无效

第一个问题是滑块的最大值设置为 audioPlayer.duration,这通常都很好,除了 HTML5 音频播放器异步加载音频资产。这意味着即使您可能在设置滑块之前加载了音频,音频资产可能尚未加载,并且 audioPlayer.duration 可能无效(可能 NaN)。

只需从滑块初始化中删除 max 键(和值),即可工作。中提琴!滑块移动!

一个警告:滑块默认为 100 个单位的最大值,音频的持续时间略高于 25 秒,因此当滑块到达 1/4 时歌曲结束播放一路走来。我们可以将 max 键设置为 25(秒),但这有点不雅,如果我们将音频更改为使用不同的源,则不会起作用。

设置滑块最大值

捕获 audioPlayer.duration 必须在处理事件时完成,一旦异步加载完成。 Javascript 提供了这样一个事件:onloadedmetadata。让我们安装一个事件处理程序,让它工作:

audioPlayer.onloadedmetadata = function() {
    $(".slider").slider("option", { max: Math.floor(audioPlayer.duration) });
};

现在,它的作用是在音频资源加载后将滑块的 max 设置为 audioPlayer.duration。实际上,这当前正在为所有滑块设置最大值,但这应该不是问题,因为它们都被隐藏了。如果您的歌曲数量非常多,可能会有一点延迟,您可能需要找到特定的滑块进行更新。

平滑滑动

现在,经过这些更改后,您可能会注意到滑块有些 跳跃。它暂停一秒钟,然后跳跃,然后暂停,等等。这可以很容易地解决,通过在滑块初始化中将 step 键更改为 0.1,如下所示:

sliderDiv.slider({
  value: 0,
  step: 0.1,
  orientation: "horizontal",

时间每 50 到 250 毫秒更新一次,但滑块只能以 1 秒为增量移动。现在,以 1/10 秒的增量,滑块将移动得更平滑。如果你愿意,你可以稍微减少一点,但不要让数字太小; 0.01 是实际的下限。

更新播放结束状态

歌曲播放完毕后,"Play" 按钮仍处于播放状态,即使不再播放任何内容。还有一个事件:onended。我们将使用该事件来更新 UI,这样用户就不会感到困惑:

audioPlayer.onended = function() {
  playButton.removeClass('fa-pause-circle-o');
  playButton.addClass('fa-play-circle-o');
};

现在,当歌曲结束时,播放按钮将返回到 "play" 状态,用户将知道点击它会播放歌曲。

重构播放按钮状态

由于现在有 3 个地方更新播放按钮的状态,这涉及重复,我们可以重构状态处理。此函数将明确设置播放按钮的状态:

function setUIState() {
  if (audioPlayer.paused || audioPlayer.ended) {
    playButton.removeClass('fa-pause-circle-o');
    playButton.addClass('fa-play-circle-o');
  } else {
    playButton.removeClass('fa-play-circle-o');
    playButton.addClass('fa-pause-circle-o');
  }
}

现在,从其他函数调用它,您最终会得到 onended 事件处理程序:

audioPlayer.onended = function() {
  setUIState();
};

changeUI函数:

function changeUI(selectedSong) {
  setUIState();

  var sliderDiv = selectedSong.parent().find('.slider');
  rebindSlider(sliderDiv);//Bind the desired slider
  $('.slider').hide(); //Hide all sliders
  sliderDiv.show();//Show only the desired slider
} 

并且,播放按钮点击处理程序:

$(".playButton").click(function() {    
  if (audioLoaded === true) {
    if (!audioPlayer.paused) {
      audioPlayer.pause();
    } else {
      audioPlayer.play();
    }
    setUIState();
  } else {
    alert("Please click a song");
  }
  return false;
});

这使得按钮的 UI 状态管理易于处理,并防止状态在应用程序中蔓延。您已经可以看到重构后的代码明显更清晰并且更易于维护。另外,作为奖励,我们必须使用很酷的 audioPlayer.ended 属性,您看不到它用得太多。

等等,还有更多!

完成上述更改后,您就可以拥有一个非常实用的音频播放器了。但这肯定不是特色功能的终点。总有成长的空间!

我创建了一个 jsFiddle,其中包含所有这些更改,以及对原始代码的一些其他修改。您可以在以下位置找到最新版本:https://jsfiddle.net/mgaskill/mp087adp/。附加功能可能会不断弹出,但 jsFiddle 已经包含这些附加功能:

  • 音量控制(滑块)
  • 时间显示
  • 为音频控件动态生成 HTML(使 HTML 更简单)