简体   繁体   English

onclick 事件需要点击两次才能工作

[英]onclick event needs clicking twice to work

I have this music player button, which needs to click twice to play it.我有这个音乐播放器按钮,需要点击两次才能播放。 It should be just clicked once它应该只被点击一次

<audio id="audio1" ontimeupdate="updateBar()" src="/musicfile/Kalimba.mp3">
        </audio>
 <span id="audioControl1" onclick="togglePlaying()">
            <i class="fa fa fa-play fa-inverse" aria-hidden="true"></i>
        </span>

Javascript Javascript

var audioEl = document.getElementById("audio1")
var ctrl = document.getElementById('audioControl1')

function togglePlaying() {
  
  var play = ctrl.innerHTML === '<i class="fa fa fa-play fa-inverse" aria-hidden="true"></i>';
  var method
  
  if (play) {
    ctrl.innerHTML = '<i class="fa fa fa-pause fa-inverse" aria-hidden="true"></i>';
    method = 'play'
  } else {
    ctrl.innerHTML = '<i class="fa fa fa-play fa-inverse" aria-hidden="true"></i>';
    method = 'pause'
  }
  
  audioEl[method]()
  
}

You are comparing html contents.您正在比较 html 内容。 Unfortunately the first time you compare html contents, the html to be compared has spaces (since you have formatted it within its parent element), and the comparison returns false.不幸的是,您第一次比较 html 的内容时,要比较的 html 有空格(因为您已在其父元素中对其进行格式化),并且比较返回 false。 But, since the html will be replaced by setting innerHTML to a new value, the html will from then on have no whitespace, allowing the next comparison to work properly.但是,由于 html 将通过将innerHTML设置为新值来替换,因此 html 从那时起将没有空格,允许下一次比较正常工作。

I recommend avoiding html comparison and innerHTML setting altogether;我建议完全避免 html 比较和innerHTML设置; use classList instead.请改用classList Note this is a working example;请注意,这是一个工作示例; click to play/pause sound:点击播放/暂停声音:

 var audioEl = document.getElementById("audio1") var ctrl = document.getElementById('audioControl1'); let togglePlaying = () => { let i = ctrl.querySelector('i'); i.classList.contains('fa-play')? (i.classList.replace('fa-play', 'fa-pause'), audioEl.play()): (i.classList.replace('fa-pause', 'fa-play'), audioEl.pause()); } let updateBar = () => {};
 i { display: block; width: 100px; height: 100px; border-radius: 100%; } i.fa-play { background-color: rgba(200, 0, 0, 1); } i.fa-pause { background-color: rgba(0, 150, 0, 1); }
 <audio id="audio1" ontimeupdate="updateBar()" src="https://www.bensound.com/bensound-music/bensound-ukulele.mp3"></audio> <span id="audioControl1" onclick="togglePlaying()"> <i class="fa fa-play fa-inverse" aria-hidden="true"></i> </span>

Your original HTML has the i element nested within the span , but you've included line breaks and spaces for indenting the code.您原来的 HTML 的i元素嵌套在span中,但您包含了用于缩进代码的换行符和空格。 Those whitespace characters become part of the span element's .innerHTML , so when you do your first check against just the i element (all in one line), the test fails, but then sets the .innerHTML to just that, so the second test succeeds.这些空白字符成为span元素的一部分.innerHTML ,所以当您第一次检查i元素(全部在一行中)时,测试失败,但随后将.innerHTML设置为那个,所以第二个测试成功.

You should strive to avoid .innerHTML for many reasons:出于多种原因,您应该努力避免使用.innerHTML

  • Problems just like this where what the actual .innerHTML is isn't what you think it is.就像这样的问题,实际的.innerHTML并不是您想象的那样。
  • There are security implications to using .innerHTML .使用.innerHTML存在安全隐患。
  • There are performance implications to using .innerHTML .使用.innerHTML会影响性能。

Instead, rely on the classes that the element in question has or doesn't have and adjust them, individually, instead of strings of HTML. Use the .classList API to do this very easily.相反,依靠相关元素具有或不具有的类并单独调整它们,而不是 HTML 的字符串。使用.classList API 可以非常轻松地完成此操作。

Also, remember not to try to run your audio until you know that it's been completely downloaded to the client.另外,请记住在您知道音频已完全下载到客户端之前不要尝试运行您的audio Do this by wrapping that code in a load event handler.通过将该代码包装在load事件处理程序中来执行此操作。

 window.addEventListener("load", function(){ var audioEl = document.getElementById("audio1"); document.getElementById('audioControl1').addEventListener("click", function() { // Find the <i> element within the clicked <span> element var control = this.querySelector("i"); if (control.classList.contains("fa-play")) { control.classList.remove("fa-play"); control.classList.add("fa-pause"); control.textContent = "Pause"; // Just for testing here audioEl.play(); } else { control.classList.add("fa-play"); control.classList.remove("fa-pause"); control.textContent = "Pause"; // Just for testing here audioEl.pause(); } }); });
 <:doctype html> <html> <head> <title>test</title> </head> <body> <audio id="audio1" src="https.//interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3"></audio> <span id="audioControl1"> <i class="fa fa-play fa-inverse" aria-hidden="true">play</i> </span> </body> </html>

If you are using an older version of font-awesome than me, change fas with fa.如果你使用的 font-awesome 版本比我的旧,请将 fas 更改为 fa。 I believe this'll absolutely work for you:我相信这绝对适合你:

 var audioEl = document.getElementById("audio1") var ctrl = document.getElementById('audioControl1') function togglePlaying() { var method; if (ctrl.getAttribute("action") == "play") { method = 'pause'; musicAction = 'play'; } else { method = 'play'; musicAction = 'pause'; } ctrl.setAttribute('action',method); ctrl.setAttribute('class','fas fa-'+method+' fa-stack-1x fa-inverse'); audioEl[musicAction]() }
 <link href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" rel="stylesheet"/> <:-- Font-Awesome Icon CDN --> <audio id="audio1" src="https.//www.bensound.com/bensound-music/bensound-ukulele.mp3"></audio> <div onclick="togglePlaying()"> <span class="fa-stack fa-2x"> <i class="fas fa-circle fa-stack-2x"></i> <i id="audioControl1" action="play" class="fas fa-play fa-stack-1x fa-inverse"></i> </span> </div>

And also you cannot use fa-inverse without fa-stack , if you want to learn why check it out: https://fontawesome.com/how-to-use/on-the-web/styling/stacking-icons如果你想了解为什么检查它,你也不能使用fa-inverse没有fa-stackhttps://fontawesome.com/how-to-use/on-the-web/styling/stacking-icons

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM