持续时间不适用于所有行

发布于 2025-02-11 20:36:24 字数 1907 浏览 1 评论 0 原文

我创建了一个与Spotify类似的音乐列表是JavaScript,我试图在所有行中添加持续时间,但问题是持续时间仅适用于第一行。控制台不显示任何错误。我尝试过,但无法弄清楚是什么问题。

// Creating Music List
const tbody = document.querySelector("tbody");
// let create tr tags according to array length for list
for (let i = 0; i < songs.length; i++) {
    //let's pass the song details from the array
    let trTag = `<tr tr-index = ${i}>
    <td class="numberlist" width="5%">${songs[i].nmbr}</td>
    <td class="title" width="80%">
        <div>
            <img class="cover1" src=${songs[i].coverPath} >
        </div>
        <div class="songdetails">
            <h3>${songs[i].trackName}</h3>
            <h4>${songs[i].trackArtist}</h4>
            
        </div>
    </td>
    <td width="30%">
        <h4>${songs[i].trackAlbum}</h4>
    </td>
    <td width="15%">${songs[i].date}</td>
    <td width="5%">
        <img class="svg1" src="/assets/asset 72.svg" alt="">
    </td>
    <td width="12%" class="audio_duration">0:00</td>
    </tr> `;


    tbody.insertAdjacentHTML("beforeend", trTag); //inserting the tr inside tbody tag

    let trAudioDuration = tbody.querySelector(".audio_duration");
    let trAudioTag = new Audio(`audio/1.mp3`);

    trAudioTag.addEventListener("loadeddata", () => {
        let aDuration = trAudioTag.duration;
        let totalMin = parseInt(aDuration / 60);
        let totalSec = parseInt(aDuration % 60);
        if (totalSec < 10) {
            totalSec = `0${totalSec}`;
        };
        trAudioDuration.innerHTML = `${totalMin}:${totalSec}`; //passing total duration of song
    });
};

I created a music list similar to spotify dynamically is javascript and I am trying to add duration in all rows but the problem is duration is applying to first row only. And console not showing any error. i tried but couldn't figure what's the problem.

// Creating Music List
const tbody = document.querySelector("tbody");
// let create tr tags according to array length for list
for (let i = 0; i < songs.length; i++) {
    //let's pass the song details from the array
    let trTag = `<tr tr-index = ${i}>
    <td class="numberlist" width="5%">${songs[i].nmbr}</td>
    <td class="title" width="80%">
        <div>
            <img class="cover1" src=${songs[i].coverPath} >
        </div>
        <div class="songdetails">
            <h3>${songs[i].trackName}</h3>
            <h4>${songs[i].trackArtist}</h4>
            
        </div>
    </td>
    <td width="30%">
        <h4>${songs[i].trackAlbum}</h4>
    </td>
    <td width="15%">${songs[i].date}</td>
    <td width="5%">
        <img class="svg1" src="/assets/asset 72.svg" alt="">
    </td>
    <td width="12%" class="audio_duration">0:00</td>
    </tr> `;


    tbody.insertAdjacentHTML("beforeend", trTag); //inserting the tr inside tbody tag

    let trAudioDuration = tbody.querySelector(".audio_duration");
    let trAudioTag = new Audio(`audio/1.mp3`);

    trAudioTag.addEventListener("loadeddata", () => {
        let aDuration = trAudioTag.duration;
        let totalMin = parseInt(aDuration / 60);
        let totalSec = parseInt(aDuration % 60);
        if (totalSec < 10) {
            totalSec = `0${totalSec}`;
        };
        trAudioDuration.innerHTML = `${totalMin}:${totalSec}`; //passing total duration of song
    });
};

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

作妖 2025-02-18 20:36:24

啊,这是一个经典的!问题在于:

let trAudioDuration = tbody.querySelector(".audio_duration");

请参阅, querySelector ,尤其是在使用类选择器时,仅返回第一个匹配的元素。我们需要在此处使用 queryselectorall ,这返回所有匹配的元素。

由于 querySelectorAll 返回多个元素的数组,因此我们还需要对InnerHtml进行一些不同的处理设置,因此我们使用 foreach 浏览所有匹配的元素并设置他们每个人都在内。

这是一个剪切,证明了问题和解决方案:

function problem() {
  let tag = document.querySelector(".duration");
  tag.innerHTML = "1:53";
}

function solution() {
  let tags = document.querySelectorAll(".duration2");
  
  tags.forEach((tag) => {
    tag.innerHTML = "8:41";
  });
}

function secure_solution() {
  let tags = document.querySelectorAll(".duration3");
  
  tags.forEach((tag) => {
    tag.textContent = "8:41";
  });
}

problem();
solution();
secure_solution();
<p>Problematic table</p>
<table id = "tbl">
  <tr><td class = "duration">0:00</td></tr>
  <tr><td class = "duration">0:00</td></tr>
  <tr><td class = "duration">0:00</td></tr>
  <tr><td class = "duration">0:00</td></tr>
  <tr><td class = "duration">0:00</td></tr>
  <tr><td class = "duration">0:00</td></tr>
</table>

<p>Working table</p>
<table id = "tbl2">
  <tr><td class = "duration2">0:00</td></tr>
  <tr><td class = "duration2">0:00</td></tr>
  <tr><td class = "duration2">0:00</td></tr>
  <tr><td class = "duration2">0:00</td></tr>
  <tr><td class = "duration2">0:00</td></tr>
  <tr><td class = "duration2">0:00</td></tr>
</table>

<p>Secure table</p>
<table id = "tbl3">
  <tr><td class = "duration3">0:00</td></tr>
  <tr><td class = "duration3">0:00</td></tr>
  <tr><td class = "duration3">0:00</td></tr>
  <tr><td class = "duration3">0:00</td></tr>
  <tr><td class = "duration3">0:00</td></tr>
  <tr><td class = "duration3">0:00</td></tr>
</table>

在重要的侧面注释您不应使用innerhtml将持续时间写入元素。您的持续时间只是文本,并且包含零HTML,因此,使用 textContent 之类的东西是一个更好的主意。这样可以确保某些恶意聚会没有机会通过以某种方式用html替换持续时间数据,例如&lt; script&gt; arter(“ hax”)&lt;/script;/script&gt; 。请注意,我实际上是如何在那里编写HTML的,但是Stackoverflow进行了考虑,您的浏览器实际上不会为您弹出一个警报框,而仅显示为文本。如果您确实需要使用 innerhtml ,请记住

Ahh, this is a classic one! The problem lies with this:

let trAudioDuration = tbody.querySelector(".audio_duration");

See, querySelector, especially when using a class selector, only returns the first matched element. We need to use querySelectorAll here instead, which returns all of the matched elements.

Since querySelectorAll returns an array of multiple elements, we also need to handle the innerHTML setting a bit differently, so we use forEach to go through all of the matched elements and set the innerHTML on each of them.

Here's a snipped demonstrating the issue and the solution:

function problem() {
  let tag = document.querySelector(".duration");
  tag.innerHTML = "1:53";
}

function solution() {
  let tags = document.querySelectorAll(".duration2");
  
  tags.forEach((tag) => {
    tag.innerHTML = "8:41";
  });
}

function secure_solution() {
  let tags = document.querySelectorAll(".duration3");
  
  tags.forEach((tag) => {
    tag.textContent = "8:41";
  });
}

problem();
solution();
secure_solution();
<p>Problematic table</p>
<table id = "tbl">
  <tr><td class = "duration">0:00</td></tr>
  <tr><td class = "duration">0:00</td></tr>
  <tr><td class = "duration">0:00</td></tr>
  <tr><td class = "duration">0:00</td></tr>
  <tr><td class = "duration">0:00</td></tr>
  <tr><td class = "duration">0:00</td></tr>
</table>

<p>Working table</p>
<table id = "tbl2">
  <tr><td class = "duration2">0:00</td></tr>
  <tr><td class = "duration2">0:00</td></tr>
  <tr><td class = "duration2">0:00</td></tr>
  <tr><td class = "duration2">0:00</td></tr>
  <tr><td class = "duration2">0:00</td></tr>
  <tr><td class = "duration2">0:00</td></tr>
</table>

<p>Secure table</p>
<table id = "tbl3">
  <tr><td class = "duration3">0:00</td></tr>
  <tr><td class = "duration3">0:00</td></tr>
  <tr><td class = "duration3">0:00</td></tr>
  <tr><td class = "duration3">0:00</td></tr>
  <tr><td class = "duration3">0:00</td></tr>
  <tr><td class = "duration3">0:00</td></tr>
</table>

On an important side note you shouldn't use innerHTML to write the duration into the elements. Your duration is just text and contains zero html, so it is a better idea to use something like textContent instead. This ensures that some malicious party has no chance of injecting their own bad HTML to your page by somehow replacing duration data with HTML like <script>alert("hax")</script>. Notice how I actually just wrote HTML there, but StackOverflow has this thought out and your browser won't actually pop an alert box for you and only shows that as a text. If you ever DO need to use innerHTML, remember to sanitize it first.

宣告ˉ结束 2025-02-18 20:36:24

您的问题是因为您的选择器 .audio_duration 正在搜索 tbody 所有 .audio_duration elements均为。

一种解决方案是获取您插入并在此上执行选择器的 tr ,然后在 .audio_duration 中查找 tr 而不是查找 .aud>。 tbody

let tr = tbody.lastElementChild;
let trAudioDuration = tr.querySelector(".audio_duration");

Your issue is because your selector .audio_duration is searching the tbody where all the .audio_duration elements are.

One solution would be to get the tr that you inserted and perform your selector on that and then it will look for .audio_duration in the tr instead of the tbody.

let tr = tbody.lastElementChild;
let trAudioDuration = tr.querySelector(".audio_duration");
鲜肉鲜肉永远不皱 2025-02-18 20:36:24

在歌曲数组中添加{src:“ AudiofilEname”},并在下面的修改代码中添加。

** - 修改的代码

const tbody = document.querySelector("tbody");
// let create tr tags according to array length for list
for (let i = 0; i < songs.length; i++) {
    //let's pass the song details from the array
    let trTag = `<tr tr-index = ${i}>
    <td class="numberlist" width="5%">${songs[i].nmbr}</td>
    <td class="title" width="80%">
        <div>
            <img class="cover1" src=${songs[i].coverPath} >
        </div>
        <div class="songdetails">
            <h3>${songs[i].trackName}</h3>
            <h4>${songs[i].trackArtist}</h4>
            
        </div>
    </td>
    <td width="30%">
        <h4>${songs[i].trackAlbum}</h4>
    </td>
    <td width="15%">${songs[i].date}</td>
    <td width="5%">
        <img class="svg1" src="/assets/asset 72.svg" alt="">
    </td>
    <td width="12%" id="${songs[i].src}" class="audio_duration">0:00</td>**
    <audio class="${songs[i].src}" src="${songs[i].filePath}"> </audio>**
    </tr > `;


    tbody.insertAdjacentHTML("beforeend", trTag); //inserting the tr inside tbody tag

    let trAudioDuration = tbody.querySelector(`#${songs[i].src}`);**
    let trAudioTag = tbody.querySelector(`.${songs[i].src}`);**

    trAudioTag.addEventListener("loadeddata", () => {
        let aDuration = trAudioTag.duration;
        let totalMin = parseInt(aDuration / 60);
        let totalSec = parseInt(aDuration % 60);
        if (totalSec < 10) {
            totalSec = `0${totalSec} `;
        };
        trAudioDuration.textContent = `${totalMin}:${totalSec} `; //passing total duration of song

    });
};```

adding {src: "audiofilename"} in song array and modifying code like below worked out.

** - modified code

const tbody = document.querySelector("tbody");
// let create tr tags according to array length for list
for (let i = 0; i < songs.length; i++) {
    //let's pass the song details from the array
    let trTag = `<tr tr-index = ${i}>
    <td class="numberlist" width="5%">${songs[i].nmbr}</td>
    <td class="title" width="80%">
        <div>
            <img class="cover1" src=${songs[i].coverPath} >
        </div>
        <div class="songdetails">
            <h3>${songs[i].trackName}</h3>
            <h4>${songs[i].trackArtist}</h4>
            
        </div>
    </td>
    <td width="30%">
        <h4>${songs[i].trackAlbum}</h4>
    </td>
    <td width="15%">${songs[i].date}</td>
    <td width="5%">
        <img class="svg1" src="/assets/asset 72.svg" alt="">
    </td>
    <td width="12%" id="${songs[i].src}" class="audio_duration">0:00</td>**
    <audio class="${songs[i].src}" src="${songs[i].filePath}"> </audio>**
    </tr > `;


    tbody.insertAdjacentHTML("beforeend", trTag); //inserting the tr inside tbody tag

    let trAudioDuration = tbody.querySelector(`#${songs[i].src}`);**
    let trAudioTag = tbody.querySelector(`.${songs[i].src}`);**

    trAudioTag.addEventListener("loadeddata", () => {
        let aDuration = trAudioTag.duration;
        let totalMin = parseInt(aDuration / 60);
        let totalSec = parseInt(aDuration % 60);
        if (totalSec < 10) {
            totalSec = `0${totalSec} `;
        };
        trAudioDuration.textContent = `${totalMin}:${totalSec} `; //passing total duration of song

    });
};```
祁梦 2025-02-18 20:36:24

如@swiffy在他的答案由于 toby> toby toby.queryselector(“。 将首先选择 .audio_duration 来自 tbody 的元素。

您可以像以下内容一样更新该查询选择器,它应该很好地工作。

let trAudioDuration = tbody.querySelector(`tr[tr-index='${i}'] .audio_duration`);
let trAudioTag = tbody.querySelector(`tr[tr-index='${i}'] audio`);

说明:

  • 选择器 tr [tr-index ='$ {i}'] .audio_duration 将在 tr element element tbody 带有属性 tr-index 及其用 i 指定的值及其任何孩子(包括儿童的孩子等)具有 audio_duration 并使用类 audio_duration 返回该元素。
  • 选择器 tr [tr-index ='$ {i}']音频将找到 tr element tbody tr-index 及其用 i 指定的值及其任何孩子(包括儿童的孩子等) audio 元素,然后返回 audio 元素。

注意: queryselector 将从给定的选择器返回第一个匹配值。如果要获取所有匹配元素,请使用

参考:

As explained by @Swiffy in his answer problem is there due to tbody.querySelector(".audio_duration"); as it will select first .audio_duration element from tbody.

You can update that query selector like below and it should work well.

let trAudioDuration = tbody.querySelector(`tr[tr-index='${i}'] .audio_duration`);
let trAudioTag = tbody.querySelector(`tr[tr-index='${i}'] audio`);

Explanation :

  • Selector tr[tr-index='${i}'] .audio_duration will find tr element inside tbody with attribute tr-index and its value specified with i and any of its child (including child of child and so on) having class audio_duration and return that element with class audio_duration.
  • Selector tr[tr-index='${i}'] audio will find tr element inside tbody with attribute tr-index and its value specified with i and any of its child (including child of child and so on) audio element and return that audio element.

Note : querySelector will return first matching value from given selector. If you want to get all matching element then use querySelectorAll.

References :

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文