student42
student42

Reputation: 171

Onmouseout not to run when moving mouse over to certain elements?

So this code makes an audio clip play when you hover over the article elements. The problem is that it stops when the mouse hover on child elements. How can I make the Stopsound function not run when the mouse hover off the general article elements and onto the child elements?

EDIT:Basically I want neither of the functions to run when when alternating which of the child element you hover over.

   function PlaySound(soundobj) {
     var thissound = document.getElementById(soundobj);
     thissound.play();
   }

   function StopSound(soundobj) {
     var thissound = document.getElementById(soundobj);
     thissound.pause();
     thissound.currentTime = 0;
   }
* {
  margin: 0;
  padding: 0;
}
article24 {
  width: 50px;
  height: 100px;
  background-color: green;
}
#box24 {
  width: 50px;
  height: 50px;
  background-color: blue;
}
#present24 {
  width: 50px;
  height: 50px;
  background-color: red;
}
#bauble24 {
  width: 10px;
  height: 10px;
}
<audio id='mySound' src="http://www.freesound.org/data/previews/278/278903_3546642-lq.mp3"></audio>
<article id="article24" onmouseover="PlaySound('mySound')" onmouseout="StopSound('mySound')">
  <div id="box24">
    <h2></h2>
  </div>
  <div id="present24">
    <a href="">
      <div id="bauble24">
        <p id="belle24">""</p>
      </div>
    </a>
  </div>
</article>

Upvotes: 2

Views: 737

Answers (2)

Scott Marcus
Scott Marcus

Reputation: 65855

Using JQuery's .hover function solves this problem as explained here.

NOTE: there are a few seconds delay in my sample file before the audio starts, so when you hover over the article wait a moment or two for the music to start.

Also, your a and div tags were incorrectly nested.

Lastly, I have removed your event binding from the HTML and moved that into the JavaScript, which is highly recommended as inline HTML event binding causes "spaghetti code", is harder debug/scale, causes anonymous global event handling wrapper functions (that alter "this" binidng) to be created and HTML event binding does not follow the much more modern and robust W3C DOM Event standard

var playing = false;

var audio = document.getElementById("mySound");
var art = document.getElementById("article24");

// We don't really need two functions for start vs. stop
// One function that simply toggles the sound based on 
// a flag will do it. JQuery's .hover method takes two
// arguments (a mouseover callback and a mouseleave callback)
$(art).hover(playStop, playStop);

function playStop(e) {
  // Check to see if we are playing or not and toggle based on that:
  if(!playing){
    audio.play();
    playing = true;
  } else {
    audio.pause();
    audio.currentTime = 0;      
    playing = false;     
  }
}
/* The following is not necessary and is only included to
   be able to visually discern the various child elements */
article { border:10px solid black; padding:10px;} 
div { border:5px solid red;}
div * {border-color: blue;}
div h2 {background:green; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<audio id='mySound' src="http://www.stephaniequinn.com/Music/Mozart%20-%20Presto.mp3"></audio>

<article id="article24">
        
  <div class="box" id="box24">
    <h2>I am in child div #1</h2>
  </div>
        
  <div id="present24">I am child div #2
    <a href="">
      <div id="bauble24">  
        <p id="belle24">I am in child div #2, but am child div #3</p>
      </div>
    </a>
  </div> 
  
</article>

Upvotes: 1

trincot
trincot

Reputation: 351084

Indeed, the mouseout event triggers whenever the mouse hovers over another element, even if that element is a child of the event's target element.

But, the mouseover event will trigger also when you stay within the bounds of the parent element, so if you could detect that event before treating the mouseout event, you could distinguish between this case and the true leaving of the parent element.

This you can do by delaying the treatment with setTimeout, and cancelling that action when you have a mouseover event following immediately:

var timer = -1; // ID of a timer we will use

function PlaySound(soundobj) {
    clearTimeout(timer); // cancel any pending StopSound action
    var thissound=document.getElementById(soundobj);
    thissound.play();
}

function StopSound(soundobj) {
    timer = setTimeout(function () { // defer the action
        var thissound=document.getElementById(soundobj);
        thissound.pause();
        thissound.currentTime = 0;
   }, 0); // 0 is enough, as the `mouseover` event is already posted in the message queue
}

Upvotes: 2

Related Questions