1

It's worth noting my actual UI is more complex but I've stripped everything back just to focus on the script needed in the example.

Issue One

I have a several div's that display content within them but also have a img or video path specified on a data-src. When hovering over an item, the relevant media (either img or video) should be added/displayed in a separate div.

In hindsight. I'm now wondering if the img/video tag shouldn't be on the page and is only added, along with the correct URL when requested?

I have the image working but not a way to check if it's an img/video and add to the relevant img or video tag. Ideally those tags wouldn't be on the page until needed but that's a bit beyond me at this stage. This should be ok as a proof of concept.

Issue Two (not a priority but I'll just mention)

I'm more than aware loading a large image or video could take time to load. So is there away to fade-in the image/video when it has loaded? I was thinking I could display a loading gif just before to give the user an indication something is happening before fading in?

const getAsset = document.querySelector('.carousel-bg img')

document.querySelectorAll('.swiper-slide').forEach(item => {
  item.onmouseover = () => getAsset.src = item.dataset.src
  item.onmouseout = () => getAsset.src = ""
})
/* Where Images Appear */

.carousel-bg {
  background: red;
  height: 300px;
  position: relative;
  margin-bottom: 10px;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  max-width: 600px;
}

.carousel-bg img,
.carousel-bg video {
  display: block;
  height: 100%;
  object-fit: cover;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
}

/* Slides */

.swiper-wrapper {
  display: flex;
}

.swiper-slide {
  background: #eee;
  margin-right: 10px;
  padding: 20px;
}

.swiper-slide img {
  
}
<div class="carousel">

  <div class="carousel-bg">
    <img src="" />
    <video autoplay muted loop>
      <source src="" type="video/mp4">
    </video>
  </div>

  <div class="swiper mySwiper">
    <div class="swiper-wrapper">
      <div class="swiper-slide" data-src="https://images.pexels.com/photos/2387418/pexels-photo-2387418.jpeg">
        Slide 1 (img)
      </div>
      <div class="swiper-slide" data-src="https://www.w3schools.com/html/mov_bbb.mp4">
        Slide 2 (vid)
      </div>
      <div class="swiper-slide" data-src="https://images.pexels.com/photos/356807/pexels-photo-356807.jpeg">
        Slide 3 (img)
      </div>
    </div>
  </div>
</div>
user1406440
  • 1,329
  • 2
  • 24
  • 59
  • Does this answers your question? [Changing source on html5 video tag](https://stackoverflow.com/questions/5235145/changing-source-on-html5-video-tag) – 0stone0 Mar 28 '23 at 11:36

1 Answers1

2

You can do it like this:

  • Get references to both imageDiv and videoDiv.
  • When onmouseover event triggers, check if the hovered element is a video by comparing the extension of the data-src attribute.
  • Depending if its a video or image, hide/show the element.
  • When onmouseout event triggers, hide both elements.

const imageDiv = document.getElementById('imageDiv');
const videoDiv = document.getElementById('videoDiv');

document.querySelectorAll('.swiper-slide').forEach(item => {
  item.onmouseover = () => {
    const dataSource = item.getAttribute("data-src");
    if(dataSource.endsWith(".mp4")){
       imageDiv.style.display = "none";
       videoDiv.style.display = "inline-block";
       videoDiv.src = dataSource;
    } else {
       imageDiv.style.display = "inline-block";
       videoDiv.style.display = "none";
       imageDiv.src = dataSource;
    }
  };
  item.onmouseout = () => {
    imageDiv.src = "";
    videoDiv.src = "";
    imageDiv.style.display = "none";
    videoDiv.style.display = "none";
  }
})
/* Where Images Appear */

.carousel-bg {
  background: red;
  height: 300px;
  position: relative;
  margin-bottom: 10px;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  max-width: 600px;
}

.carousel-bg img,
.carousel-bg video {
  display: block;
  height: 100%;
  object-fit: cover;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
}

/* Slides */

.swiper-wrapper {
  display: flex;
}

.swiper-slide {
  background: #eee;
  margin-right: 10px;
  padding: 20px;
}

.swiper-slide img {
  
}
<div class="carousel">

  <div class="carousel-bg">
    <img src="" id="imageDiv" style="display:none"/>
    <video autoplay muted loop id="videoDiv" style="display:none">
      <source src="" type="video/mp4">
    </video>
  </div>

  <div class="swiper mySwiper">
    <div class="swiper-wrapper">
      <div class="swiper-slide" data-src="https://images.pexels.com/photos/2387418/pexels-photo-2387418.jpeg">
        Slide 1 (img)
      </div>
      <div class="swiper-slide" data-src="https://www.w3schools.com/html/mov_bbb.mp4">
        Slide 2 (vid)
      </div>
      <div class="swiper-slide" data-src="https://images.pexels.com/photos/356807/pexels-photo-356807.jpeg">
        Slide 3 (img)
      </div>
    </div>
  </div>
</div>
NeNaD
  • 18,172
  • 8
  • 47
  • 89
  • 1
    Nice! Just having a play around with this. General question, do you think it's ok to have empty video/img tags on the page? I might try and work in an add/remove `visible` class to I can change opacity and fade in rather the display so it's a bit smoother. – user1406440 Mar 28 '23 at 12:04
  • 1
    You can dynamically create an element inside `carousel-bg` div. So, initially it will be empty, and you will create a child element inside `onmouseover` event handler which will be either `img` or `video`. Also, you should remove the previous child if it already exists. – NeNaD Mar 28 '23 at 13:15
  • 1
    Cool, seems like this does the trick, I'll just trying updating after work. Class/opacity instead of `display` should be easy to switch. Then try I'll try using `createElement(" and see what behaves better. – user1406440 Mar 28 '23 at 14:19