You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django音乐流媒体网站JS播放异常:点击歌曲始终显示首歌元信息

修复方案:Django音乐网站播放器信息不更新问题

问题场景

开发基于Django的音乐流媒体网站,实现了点击歌曲在统一播放器播放的功能,但点击任意歌曲时,播放器始终显示第一首歌的名称、歌手和封面图片,仅音频播放正常。

现有代码

JavaScript函数

function playSong(element){
        var songUrl = element.getAttribute('data-song-url');
        var audioPlayer = document.getElementById('audioPlayer');
        var audioSource = document.getElementById('audioSource');
        audioSource.src = songUrl;
        audioPlayer.load();
        audioPlayer.play();
        var songId = element.id;
        var newImage = document.getElementById("A_" + songId).src;
        var newSongName = document.getElementById("B_" + songId).textContent;
        var newArtistName = document.getElementById("C_" + songId).textContent;
        console.log(newSongName) //always displaying the things of the first song
        console.log(newImage)
        console.log(newArtistName)
        
        document.getElementById("audio-img").src = newImage;
        document.getElementById("audio-song").textContent = newSongName;
        document.getElementById("audio-artist").textContent = newArtistName;
    }

Django模板HTML

{% for i in songs %}
            <div class="carousel-cell">
                <section class="main_song">
                    <div class="song-card">
                        <div class="containera">
                            <img src="{{i.image}}" id="A_{{i.id}}" alt="song cover">
                            <div class="overlaya"></div>
                            <div>
                                <a class="play-btn" data-song-url="{{i.song.url}}" id="{{i.id}}" onclick="playSong(this)"><i class="fas fa-play-circle fa-2x"></i></a>
                                {% if user.is_authenticated %}
                                    <div class="add-playlist-btn">
                                        <a id="W_{{i.song_id}}" title="Add to Playlist" onclick="showDiv(this)"><i class="fas fa-ellipsis-h"></i></a>
                                    </div>
                                {% endif %}
                            </div>
                        </div>
                    </div>
                    <div>
                        <p class="songName" id="B_{{i.id}}">{{i.name}}</p>
                        <p class="artistName" id="C_{{i.id}}">{{i.artist}}</p>
                    </div>
                </section>
            </div>
  {% endfor %}

问题原因

核心问题是依赖ID获取元素的方式存在隐患:要么是循环中生成的id="{{i.id}}"并非唯一值(比如songs中的对象ID重复),要么是DOM中存在多个相同ID的元素,导致getElementById始终返回第一个匹配的元素。

修复方案

推荐两种可靠的修复方式,无需依赖ID:

方案1:通过DOM遍历获取当前歌曲信息

利用closest和querySelector从点击元素的上级节点定位到当前歌曲卡片的信息,避免ID依赖:

function playSong(element){
    var songUrl = element.getAttribute('data-song-url');
    var audioPlayer = document.getElementById('audioPlayer');
    var audioSource = document.getElementById('audioSource');
    audioSource.src = songUrl;
    audioPlayer.load();
    audioPlayer.play();

    // 定位到当前歌曲的父级卡片容器
    var songCard = element.closest('.main_song');
    // 从卡片中提取信息
    var newImage = songCard.querySelector('.containera img').src;
    var newSongName = songCard.querySelector('.songName').textContent;
    var newArtistName = songCard.querySelector('.artistName').textContent;

    console.log(newSongName);
    console.log(newImage);
    console.log(newArtistName);
    
    // 更新播放器信息
    document.getElementById("audio-img").src = newImage;
    document.getElementById("audio-song").textContent = newSongName;
    document.getElementById("audio-artist").textContent = newArtistName;
}

方案2:通过Data属性直接传递信息

将歌曲的名称、歌手、封面地址直接存在点击按钮的data-*属性中,直接读取无需DOM遍历:

修改Django模板

{% for i in songs %}
    <div class="carousel-cell">
        <section class="main_song">
            <div class="song-card">
                <div class="containera">
                    <img src="{{i.image}}" alt="song cover">
                    <div class="overlaya"></div>
                    <div>
                        <a class="play-btn" 
                           data-song-url="{{i.song.url}}" 
                           data-song-name="{{i.name}}" 
                           data-artist-name="{{i.artist}}" 
                           data-image-url="{{i.image}}"
                           onclick="playSong(this)">
                            <i class="fas fa-play-circle fa-2x"></i>
                        </a>
                        {% if user.is_authenticated %}
                            <div class="add-playlist-btn">
                                <a id="W_{{i.song_id}}" title="Add to Playlist" onclick="showDiv(this)"><i class="fas fa-ellipsis-h"></i></a>
                            </div>
                        {% endif %}
                    </div>
                </div>
            </div>
            <div>
                <p class="songName">{{i.name}}</p>
                <p class="artistName">{{i.artist}}</p>
            </div>
        </section>
    </div>
{% endfor %}

修改JavaScript函数

function playSong(element){
    var songUrl = element.getAttribute('data-song-url');
    var audioPlayer = document.getElementById('audioPlayer');
    var audioSource = document.getElementById('audioSource');
    audioSource.src = songUrl;
    audioPlayer.load();
    audioPlayer.play();

    // 直接从Data属性读取歌曲信息
    var newImage = element.getAttribute('data-image-url');
    var newSongName = element.getAttribute('data-song-name');
    var newArtistName = element.getAttribute('data-artist-name');

    console.log(newSongName);
    console.log(newImage);
    console.log(newArtistName);
    
    // 更新播放器信息
    document.getElementById("audio-img").src = newImage;
    document.getElementById("audio-song").textContent = newSongName;
    document.getElementById("audio-artist").textContent = newArtistName;
}

内容的提问来源于stack exchange,提问作者Federico Monetti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 08:58:11