向YouTube Iframe API播放列表队列添加视频时索引异常问题
问题:YouTube Iframe API 播放列表索引异常导致切换功能失效
我在Web应用中使用YouTube Iframe API,向已有播放列表添加视频后出现异常:播放列表索引变为非整数,导致nextVideo和previousVideo功能失效,这两个功能在其他场景下正常工作。
相关代码
_mediaplayer.html.erb(媒体播放器模板片段)
<div id="media-player" class="playing"> <marquee>Now playing: <span id="track-title"></span></marquee> <div class="controls"> <button aria-label="play" id="play" class="play">Play</button> <button aria-label="stop" id="stop" class="stop">Stop</button> <button aria-label="previous track" id="prev" class="prev">Prev</button> <button aria-label="next track" id="next" class="next">Next</button> <div class="current-time-container"> <span id="curr-main" class="current-time"></span> </div> </div> <div class="range-container"> <input id="dur-main" type="range" name="rng" min="0" value="0" max="252.029388"> </div> </div> <div controls data-autoplay="0" data-loop="1" id="youtube-player">Youtube Player</div>
youtubePlayer.js(播放器控制逻辑)
// initialize youtube player const player = new YT.Player('youtube-player', { width: 300, height: 200, }); document.addEventListener('turbo:load', youtube_player, false); document.addEventListener('turbo:frame-load', youtube_player, false); function youtube_player () { let playlist = document.getElementById('cuePlaylist').dataset.playlist.split(','); // define media player controls const playAll = document.getElementById("playPlaylist"), cue = document.getElementById("cuePlaylist"), play = document.getElementById("play"), stop = document.getElementById("stop"), prev = document.getElementById("prev"), next = document.getElementById("next"); cue.addEventListener("click", function(e){ e.preventDefault(); if (player.getPlaylist()) { const new_playlist = player.getPlaylist().concat(playlist); if (player.getPlayerState() == YT.PlayerState.PLAYING) { player.loadPlaylist(new_playlist, player.getCurrentTime(), player.getPlaylistIndex()); play.innerHTML = "Pause"; } else { player.cuePlaylist(new_playlist); } } else { player.cuePlaylist(playlist); } }); playAll.addEventListener("click", function(e) { e.preventDefault(); player.loadPlaylist(playlist); play.innerHTML = "Pause"; }); play.addEventListener("click", function() { if (player.getPlayerState() == YT.PlayerState.PLAYING) { player.pauseVideo(); play.innerHTML = "Play"; } else { player.playVideo(); play.innerHTML = "Pause"; } }); stop.addEventListener("click", function() { if (player.getPlayerState() == YT.PlayerState.PLAYING) { player.stopVideo(); play.innerHTML = "Play"; } }); prev.addEventListener("click", function() { if (player.getPlayerState() == YT.PlayerState.PLAYING) { player.previousVideo(); } else { player.previousVideo(); player.pauseVideo(); } }); next.addEventListener("click", function() { if (player.getPlayerState() == YT.PlayerState.PLAYING) { player.nextVideo(); } else { player.nextVideo(); player.pauseVideo(); } }); }
show.html.erb(播放列表展示页面)
<section class="playlist"> <div class="site-container"> <% if @playlist.image.attached? %> <%= image_tag @playlist.image, size: "100x100", alt: "#{@playlist.title} image", class: "playlist-image" %> <% end %> <div class="copy-area"> <h1 class="playlist-title"><%= @playlist.title %></h1> <% if @is_user %> <p class="playlist_user">By you</p> <div class="playlist-actions"> <%= link_to "Add editor", search_users_path %> <%= link_to "Edit", edit_playlist_path(@playlist) %> <%= button_to "Delete", @playlist, method: :delete %> </div> <% else %> <p class="playlist-user">By <%= @user.username ? @user.username : @user.email %></p> <% end %> # Editors <% if @playlist.editors.present? %> <div class="playlist-editors"> <% @playlist.editors.each do |editor| %> <%= link_to editor.username, user_account_path(editor) %> <% end %> </div> <% end %> # Tags <% if @playlist.tags %> <div class="playlist-tags"> <% @playlist.tags.each do |tag| %> <%= render "tags/tag", tag: tag, is_user: @is_user %> <% end %> </div> <% end %> </div> # Tracks <% if @tracks %> <% index = 0 %> <%= link_to "Play Playlist", '#', id: 'playPlaylist', data: {turbo_frame: 'mediaplayer'} %> <%= link_to "Add to queue", '#', id: 'cuePlaylist', data: {'playlist' => @track_ids.join(','), turbo_frame: 'mediaplayer'} %> <div id="tracklist" class="playlist-tracks"> <% for track in @tracks %> <%= render "tracks/track", track: track, index: index, user: @user %> <% index += 1 %> <% end %> </div> <% end %> </div> </section>
问题定位与修复思路
- 核心问题:调用
loadPlaylist时传入的起始索引可能因API内部精度问题变为非整数,导致切换功能失效;同时存在turbo事件触发时重复绑定事件的潜在风险。 - 修复步骤:
- 强制索引为整数:在调用
loadPlaylist时,将player.getPlaylistIndex()转换为整数,避免浮点值传入:// 修改cue事件中的loadPlaylist调用 const currentIndex = parseInt(player.getPlaylistIndex(), 10); player.loadPlaylist(new_playlist, player.getCurrentTime(), currentIndex); - 过滤无效播放列表条目:确保拼接后的播放列表无空值或无效ID,避免索引计算错误:
const new_playlist = player.getPlaylist().concat(playlist).filter(id => id.trim() !== ''); - 避免重复绑定事件:添加初始化标识,防止turbo事件重复触发时重复绑定事件:
let isPlayerEventsBound = false; function youtube_player () { if (isPlayerEventsBound) return; isPlayerEventsBound = true; // 原有代码逻辑... } - 调试验证索引值:在关键位置打印索引值,确认转换后为整数:
console.log('原始索引:', player.getPlaylistIndex()); const currentIndex = parseInt(player.getPlaylistIndex(), 10); console.log('转换后索引:', currentIndex);
- 强制索引为整数:在调用
内容的提问来源于stack exchange,提问作者Jillian Hoenig
相关产品推荐
相关产品推荐

