使用 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 音频,具有一个音频元素和多个滑块。
现在的问题是:
- 滑块不随音频动画。
- 滑块不定位到音频。
- 以前,当以上两个都起作用时,一旦您在歌曲中选择了一个位置,滑块将不再有动画效果。
我已经创建了点击新歌时 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 更简单)
感谢您查看我的问题。 Fiddle 是 HERE.
我正在尝试为页面上的许多歌曲实现音频播放器。这是使用 JQueryUI 滑块和 HTML5 音频,具有一个音频元素和多个滑块。
现在的问题是:
- 滑块不随音频动画。
- 滑块不定位到音频。
- 以前,当以上两个都起作用时,一旦您在歌曲中选择了一个位置,滑块将不再有动画效果。
我已经创建了点击新歌时 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 更简单)