使用通过自定义数据属性检索的选择器在音频播放时显示目标 div
Show a target div on audio play with a selector retrieved via a custom data attribute
我有一个带有多首歌曲的音频播放器。对于每首歌曲,我想在下面显示一个 div
,其中包含该特定歌曲的歌词,同时隐藏所有其他歌曲的歌词。
这是音频播放器的脚本,有效:
initAudio($('#playlist li:first-child'));
function initAudio(element){
var song = element.attr('song');
var title = element.text();
var cover = element.attr('cover');
var artist = element.attr('artist');
var album = element.attr('album');
//Create audio object
audio = new Audio('public/songs/'+ song);
//Insert audio info
$('.artist').text(artist);
$('.title').text(title);
$('.album').text(album);
//Insert song cover
$('img.cover').attr('src','public/images/' + cover);
$('#playlist li').removeClass('active');
element.addClass('active');
// Set timer to 0
$('#duration').html('0:00');
// Maintain volume on song change
audio.volume = $('#volume').val() / 100;
}
这里是播放列表和歌词的简化版本HTML:
<ul id="playlist">
<li class="song-list active" song="song-1.wav" data-id="song-1"></li>
<li class="song-list" song="song-2.wav" data-id="song-2"></li>
<li class="song-list" song="song-3.wav" data-id="song-3"></li>
</ul>
<div id="song-1" class="lyrics">Lyrics to song 1</div>
<div id="song-2" class="lyrics">Lyrics to song 2</div>
<div id="song-3" class="lyrics">Lyrics to song 3</div>
我试了很多东西,都无济于事。我什至不确定如何在每首歌曲播放时定位它以提取 data-attribute
。
有什么想法吗?
注意:对于接下来的步骤,我们假设目标为 "song-1"。
- 通过调用
element.attr('data-id')
获取 data-id
属性;
returns 字符串 "song-1".
- 通过调用
$('#song-1')
以 id="song-1"
定位 DOM 元素;
这将是 $('#' + element.attr('data-id'))
(如果您不知道为什么,请查看第 1 步)。
- 既然我们有了目标,我们应该提前隐藏所有其他歌词
$('.lyrics').hide()
,只显示想要的歌词$('#' + element.attr('data-id')).show()
。
initAudio($('#playlist li:first-child'));
function initAudio( element ) {
// this version performs slightly better than the one in the 1, 2, 3 explanations
$('.lyrics').hide().filter('#' + element.attr('data-id')).show()
}
$('#playlist').on('click', function( oEvent ) {
initAudio( $( oEvent.target ) )
} );
<ul id="playlist">
<li class="song-list active" song="song-1.wav" data-id="song-1">Click Me 1!</li>
<li class="song-list" song="song-2.wav" data-id="song-2">Click Me 2!</li>
<li class="song-list" song="song-3.wav" data-id="song-3">Click Me 3!</li>
</ul>
<div id="song-1" class="lyrics">Lyrics to song 1</div>
<div id="song-2" class="lyrics">Lyrics to song 2</div>
<div id="song-3" class="lyrics">Lyrics to song 3</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
这可以像您希望的那样工作(我希望如此 - 至少)但不是一个理想的解决方案;只是想解释发生了什么!上述解决方案的缺点是大量不必要的计算。
这是一个高级模型(计算较少):
//initAudio($('#playlist li:first-child'));
initAudio($('#playlist').find('li:first-child')); // performs better
function initAudio( element ) {
// if you chain it this way you don't have to cache $('.lyrics')
$('.lyrics') // get collection of all div.lyrics
.filter('.active').removeClass('active') // target the current div.lyrics.active and remove class "active"
.end() // get collection div.lyrics back again
.filter('#' + element.attr('data-id')).addClass('active'); // filter target div.lyrics#song-[1|2|3] and add class "active"
}
$('#playlist').on('click', function( oEvent ) {
initAudio( $( oEvent.target ) )
} );
.lyrics { /* this will prevent to show all lyrics before you call initAudio() */
display: none;
}
.lyrics.active { /* style active lyrics as you like */
display: initial;
}
<ul id="playlist">
<li class="song-list active" song="song-1.wav" data-id="song-1">Click Me 1!</li>
<li class="song-list" song="song-2.wav" data-id="song-2">Click Me 2!</li>
<li class="song-list" song="song-3.wav" data-id="song-3">Click Me 3!</li>
</ul>
<!-- set one as active in advance if you like -->
<div id="song-1" class="lyrics active">Lyrics to song 1</div>
<div id="song-2" class="lyrics">Lyrics to song 2</div>
<div id="song-3" class="lyrics">Lyrics to song 3</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
额外推荐
要在使用自定义 HTML5 属性时保持有效标记,只需在您的属性前添加 data-
。
所以考虑改变
song="song-#.wav"
至
data-song="song-#.wav"
并且您的标记将有效。 (其他属性也相同 cover
到 data-cover
、artist
到 data-artist
等)。
- https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
- https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#attr-dataset
OP
中未使用的 jQuery 方法的参考
额外的灵感
根据您构建网站的方式,还有比使用 data-*
属性将数据存储到标记中更直接的解决方案。
为什么不将数据与实际数据分开 HTML。为此,您可以将数据部署为变量。
var sIdCurrent = undefined,
oData = {
'song-1': { artist: 'artist 1', lyrics: 'Lyrics to song 1' },
'song-2': { artist: 'artist 2', lyrics: 'Lyrics to song 2' },
'song-3': { artist: 'artist 3', lyrics: 'Lyrics to song 3' },
};
function initAudio( sId ) {
if ( sId === sIdCurrent ) return;
sIdCurrent = sId;
//$('#artist').find('span').text( oData[ sId ].artist );
//$('#lyrics').find('span').text( oData[ sId ].lyrics );
// the above can be abstracted to
for ( sKey in oData[ sId ] ) {
$('#' + sKey).find('span').text( oData[ sId ][ sKey ] );
}
}
initAudio('song-1');
$('#playlist').on('click', function( oEvent ) {
initAudio( oEvent.target.id )
} );
<!-- As you can see the markup is much cleaner now.
No need to store data uneffectively in markup. -->
<ul id="playlist">
<li class="song-list active" id="song-1">Click Me 1!</li>
<li class="song-list" id="song-2">Click Me 2!</li>
<li class="song-list" id="song-3">Click Me 3!</li>
</ul>
<div id="artist">Artist: <span><span></div>
<div id="lyrics">Lyrics: <span><span></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Song List Sample</title>
<script type="text/javascript" language="javascript" src="./scripts/jquery-3.2.1.min.js"></script>
<script type="text/javascript" language="javascript">
var audio = null;
function initAudio(songElem)
{
var songID = null;
var title = null;
var metaID = null;
var songFile = null;
var cover = null;
var artist = null;
var album = null;
try
{
// Retrieve song Title and meta-data identifier
songID = "#" + songElem.getAttribute("id");
title = $(songID).text();
metaID = "#" + $(songID).attr('data-id');
// Get selected song data
songFile = $(metaID).attr('song');
cover = $(metaID).attr('cover');
artist = $(metaID).attr('artist');
album = $(metaID).attr('album');
// Update summary to be displayed
$("#currentTitle").text(title);
$("#currentAlbum").text(album);
$("#currentArtist").text(artist);
$("#currentCover img").attr("src", cover);
// Hide and display applicable song data
$(".songmeta").hide();
$("#currentSong").show();
$(metaID).show();
// Create or update audio object
if (audio != null) audio.src = songFile;
else audio = new Audio(songFile);
audio.play();
// Update current song selection
$(".songlist").attr("active", "false");
$(songID).attr("active", "true");
}
catch (e)
{
alert("initAudio Error: " + e.Message);
}
finally
{
}
}
</script>
</head>
<body>
<ul id="playlist">
<li id="s1" class="song-list" onclick="initAudio(this)" active="false" data-id="song-1">Song One</li>
<li id="s2" class="song-list" onclick="initAudio(this)" active="false" data-id="song-2">Song Two</li>
<li id="s3" class="song-list" onclick="initAudio(this)" active="false" data-id="song-3">Song Three</li>
</ul>
<div id="currentSong" >
<table border="1">
<tr>
<td>
<table border="1">
<tr><td><b>Song</b></td><td id="currentTitle"></td></tr>
<tr><td><b>Album</b></td><td id="currentAlbum"></td></tr>
<tr><td><b>Artist</b></td><td id="currentArtist"></td></tr>
</table>
</td>
<td id="currentCover"><img alt="" src="" /></td>
</tr>
</table>
</div>
<div id="song-1" class="songmeta" artist="Song 1 Artist" album="Song 1 Album" cover="./images/Album1.jpeg" song="./songs/Song1.mp3" >Lyrics to song 1</div>
<div id="song-2" class="songmeta" artist="Song 2 Artist" album="Song 2 Album" cover="./images/Album2.jpeg" song="./songs/Song2.mp3" >Lyrics to song 2</div>
<div id="song-3" class="songmeta" artist="Song 3 Artist" album="Song 3 Album" cover="./images/Album3.jpeg" song="./songs/Song3.mp3" >Lyrics to song 3</div>
<script type="text/javascript" language="javascript">
// Initialization
$(".songmeta").hide();
$("#currentSong").hide();
</script>
</body>
</html>
我有一个带有多首歌曲的音频播放器。对于每首歌曲,我想在下面显示一个 div
,其中包含该特定歌曲的歌词,同时隐藏所有其他歌曲的歌词。
这是音频播放器的脚本,有效:
initAudio($('#playlist li:first-child'));
function initAudio(element){
var song = element.attr('song');
var title = element.text();
var cover = element.attr('cover');
var artist = element.attr('artist');
var album = element.attr('album');
//Create audio object
audio = new Audio('public/songs/'+ song);
//Insert audio info
$('.artist').text(artist);
$('.title').text(title);
$('.album').text(album);
//Insert song cover
$('img.cover').attr('src','public/images/' + cover);
$('#playlist li').removeClass('active');
element.addClass('active');
// Set timer to 0
$('#duration').html('0:00');
// Maintain volume on song change
audio.volume = $('#volume').val() / 100;
}
这里是播放列表和歌词的简化版本HTML:
<ul id="playlist">
<li class="song-list active" song="song-1.wav" data-id="song-1"></li>
<li class="song-list" song="song-2.wav" data-id="song-2"></li>
<li class="song-list" song="song-3.wav" data-id="song-3"></li>
</ul>
<div id="song-1" class="lyrics">Lyrics to song 1</div>
<div id="song-2" class="lyrics">Lyrics to song 2</div>
<div id="song-3" class="lyrics">Lyrics to song 3</div>
我试了很多东西,都无济于事。我什至不确定如何在每首歌曲播放时定位它以提取 data-attribute
。
有什么想法吗?
注意:对于接下来的步骤,我们假设目标为 "song-1"。
- 通过调用
element.attr('data-id')
获取data-id
属性;
returns 字符串 "song-1". - 通过调用
$('#song-1')
以id="song-1"
定位 DOM 元素;
这将是$('#' + element.attr('data-id'))
(如果您不知道为什么,请查看第 1 步)。 - 既然我们有了目标,我们应该提前隐藏所有其他歌词
$('.lyrics').hide()
,只显示想要的歌词$('#' + element.attr('data-id')).show()
。
initAudio($('#playlist li:first-child'));
function initAudio( element ) {
// this version performs slightly better than the one in the 1, 2, 3 explanations
$('.lyrics').hide().filter('#' + element.attr('data-id')).show()
}
$('#playlist').on('click', function( oEvent ) {
initAudio( $( oEvent.target ) )
} );
<ul id="playlist">
<li class="song-list active" song="song-1.wav" data-id="song-1">Click Me 1!</li>
<li class="song-list" song="song-2.wav" data-id="song-2">Click Me 2!</li>
<li class="song-list" song="song-3.wav" data-id="song-3">Click Me 3!</li>
</ul>
<div id="song-1" class="lyrics">Lyrics to song 1</div>
<div id="song-2" class="lyrics">Lyrics to song 2</div>
<div id="song-3" class="lyrics">Lyrics to song 3</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
这可以像您希望的那样工作(我希望如此 - 至少)但不是一个理想的解决方案;只是想解释发生了什么!上述解决方案的缺点是大量不必要的计算。
这是一个高级模型(计算较少):
//initAudio($('#playlist li:first-child'));
initAudio($('#playlist').find('li:first-child')); // performs better
function initAudio( element ) {
// if you chain it this way you don't have to cache $('.lyrics')
$('.lyrics') // get collection of all div.lyrics
.filter('.active').removeClass('active') // target the current div.lyrics.active and remove class "active"
.end() // get collection div.lyrics back again
.filter('#' + element.attr('data-id')).addClass('active'); // filter target div.lyrics#song-[1|2|3] and add class "active"
}
$('#playlist').on('click', function( oEvent ) {
initAudio( $( oEvent.target ) )
} );
.lyrics { /* this will prevent to show all lyrics before you call initAudio() */
display: none;
}
.lyrics.active { /* style active lyrics as you like */
display: initial;
}
<ul id="playlist">
<li class="song-list active" song="song-1.wav" data-id="song-1">Click Me 1!</li>
<li class="song-list" song="song-2.wav" data-id="song-2">Click Me 2!</li>
<li class="song-list" song="song-3.wav" data-id="song-3">Click Me 3!</li>
</ul>
<!-- set one as active in advance if you like -->
<div id="song-1" class="lyrics active">Lyrics to song 1</div>
<div id="song-2" class="lyrics">Lyrics to song 2</div>
<div id="song-3" class="lyrics">Lyrics to song 3</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
额外推荐
要在使用自定义 HTML5 属性时保持有效标记,只需在您的属性前添加 data-
。
所以考虑改变
song="song-#.wav"
至
data-song="song-#.wav"
并且您的标记将有效。 (其他属性也相同 cover
到 data-cover
、artist
到 data-artist
等)。
- https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
- https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#attr-dataset
OP
中未使用的 jQuery 方法的参考额外的灵感
根据您构建网站的方式,还有比使用 data-*
属性将数据存储到标记中更直接的解决方案。
为什么不将数据与实际数据分开 HTML。为此,您可以将数据部署为变量。
var sIdCurrent = undefined,
oData = {
'song-1': { artist: 'artist 1', lyrics: 'Lyrics to song 1' },
'song-2': { artist: 'artist 2', lyrics: 'Lyrics to song 2' },
'song-3': { artist: 'artist 3', lyrics: 'Lyrics to song 3' },
};
function initAudio( sId ) {
if ( sId === sIdCurrent ) return;
sIdCurrent = sId;
//$('#artist').find('span').text( oData[ sId ].artist );
//$('#lyrics').find('span').text( oData[ sId ].lyrics );
// the above can be abstracted to
for ( sKey in oData[ sId ] ) {
$('#' + sKey).find('span').text( oData[ sId ][ sKey ] );
}
}
initAudio('song-1');
$('#playlist').on('click', function( oEvent ) {
initAudio( oEvent.target.id )
} );
<!-- As you can see the markup is much cleaner now.
No need to store data uneffectively in markup. -->
<ul id="playlist">
<li class="song-list active" id="song-1">Click Me 1!</li>
<li class="song-list" id="song-2">Click Me 2!</li>
<li class="song-list" id="song-3">Click Me 3!</li>
</ul>
<div id="artist">Artist: <span><span></div>
<div id="lyrics">Lyrics: <span><span></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Song List Sample</title>
<script type="text/javascript" language="javascript" src="./scripts/jquery-3.2.1.min.js"></script>
<script type="text/javascript" language="javascript">
var audio = null;
function initAudio(songElem)
{
var songID = null;
var title = null;
var metaID = null;
var songFile = null;
var cover = null;
var artist = null;
var album = null;
try
{
// Retrieve song Title and meta-data identifier
songID = "#" + songElem.getAttribute("id");
title = $(songID).text();
metaID = "#" + $(songID).attr('data-id');
// Get selected song data
songFile = $(metaID).attr('song');
cover = $(metaID).attr('cover');
artist = $(metaID).attr('artist');
album = $(metaID).attr('album');
// Update summary to be displayed
$("#currentTitle").text(title);
$("#currentAlbum").text(album);
$("#currentArtist").text(artist);
$("#currentCover img").attr("src", cover);
// Hide and display applicable song data
$(".songmeta").hide();
$("#currentSong").show();
$(metaID).show();
// Create or update audio object
if (audio != null) audio.src = songFile;
else audio = new Audio(songFile);
audio.play();
// Update current song selection
$(".songlist").attr("active", "false");
$(songID).attr("active", "true");
}
catch (e)
{
alert("initAudio Error: " + e.Message);
}
finally
{
}
}
</script>
</head>
<body>
<ul id="playlist">
<li id="s1" class="song-list" onclick="initAudio(this)" active="false" data-id="song-1">Song One</li>
<li id="s2" class="song-list" onclick="initAudio(this)" active="false" data-id="song-2">Song Two</li>
<li id="s3" class="song-list" onclick="initAudio(this)" active="false" data-id="song-3">Song Three</li>
</ul>
<div id="currentSong" >
<table border="1">
<tr>
<td>
<table border="1">
<tr><td><b>Song</b></td><td id="currentTitle"></td></tr>
<tr><td><b>Album</b></td><td id="currentAlbum"></td></tr>
<tr><td><b>Artist</b></td><td id="currentArtist"></td></tr>
</table>
</td>
<td id="currentCover"><img alt="" src="" /></td>
</tr>
</table>
</div>
<div id="song-1" class="songmeta" artist="Song 1 Artist" album="Song 1 Album" cover="./images/Album1.jpeg" song="./songs/Song1.mp3" >Lyrics to song 1</div>
<div id="song-2" class="songmeta" artist="Song 2 Artist" album="Song 2 Album" cover="./images/Album2.jpeg" song="./songs/Song2.mp3" >Lyrics to song 2</div>
<div id="song-3" class="songmeta" artist="Song 3 Artist" album="Song 3 Album" cover="./images/Album3.jpeg" song="./songs/Song3.mp3" >Lyrics to song 3</div>
<script type="text/javascript" language="javascript">
// Initialization
$(".songmeta").hide();
$("#currentSong").hide();
</script>
</body>
</html>