I'm trying to make a gallery of videos that play on hover...and only when hovered. But for some reason, sometimes the videos continue to play even when the mouse exits them.
I'm using aurelia's mouseover.delegate="hoverVideo($index)"
and mouseout.delegate="hideVideo($index)"
to initiate the playback.
hoverVideo = index => {
let id = "#video" + "-" + index.toString();
let isPlaying =
$(id).get(0).currentTime > 0 &&
!$(id).get(0).paused &&
!$(id).get(0).ended &&
$(id).get(0).readyState > 2;
if (!isPlaying) {
$(id)
.get(0)
.play();
}
};
hideVideo = index => {
let id = "#video" + "-" + index.toString();
let isPlaying =
$(id).get(0).currentTime > 0 &&
!$(id).get(0).paused &&
!$(id).get(0).ended &&
$(id).get(0).readyState > 2;
if (isPlaying) {
$(id)
.get(0)
.pause();
}
};
How do I get the videos to ALWAYS stop playing on mouse exit?
Try using mouseenter.trigger
and mouseleave.trigger
. Trigger event listeners are attached directly to the html element (as opposed to on the body tag like delegates are) and can be a little more responsive depending on how big your pages age.
Additionally, you could try wrapping (some of) your event handler logic in a TaskQueue.queueMicroTask
call inside the event callbacks. This executes your code the next requestAnimationFrame
and ensures the element is ready to respond to your changes.
And perhaps store the element in a variable so you don't need to query the DOM more than once.
Example:
hideVideo = index => {
const id = "#video" + "-" + index.toString();
const video = $(id).get(0);
const isPlaying = video.currentTime > 0
&& !video.paused
&& !video.ended
&& video.readyState > 2;
if (isPlaying) {
// if the element is still somehow busy during mouseleave
this.taskQueue.queueMicroTask(() => {
video.pause();
});
}
}
Or:
hideVideo = index => {
const id = "#video" + "-" + index.toString();
const video = $(id).get(0);
// if the state isn't always up-to-date in time
this.taskQueue.queueMicroTask(() => {
const isPlaying = video.currentTime > 0
&& !video.paused
&& !video.ended
&& video.readyState > 2;
if (isPlaying) {
video.pause();
}
});
}
If that still doesn't work, maybe the state of the video is not what you're expecting it to be. An operation like pause()
should be idempotent, so you could try just skipping the isPlaying
check altogether.