0

I have 2 videos that work like Instagram reels, when a user clicks the first video it starts playing, but if they scroll to the next video and click to start it the previous video keeps playing. What I would like is only the video in the current view to play and all other videos be paused but cant seem to figure it out. Ideally just autoplay the video in the viewport and auto-pause the rest. I've looked at similar issues on Stack but have had no luck achieving this.

The HTML

<div class="app__videos">
  <div class="video">
      <video src="video1.mp4" class="video__player"></video>
  </div> 
  
  <div class="video">
      <video src="video2.mp4"></video>
  </div> 
</div>

The JS

function loadVideos(){
  var videos = document.querySelectorAll('video');
  for(const video of videos){
      // ive tried changing the click function to scroll but didn't work
      video.addEventListener('click', function(){
        if(video.paused){
          video.play();
        }else{
          video.pause()
        }
      });
  }
}

loadVideos()

** Edit

// Tried adding a scrolling event listener

function loadVideos(){
  var videos = document.querySelectorAll('video');
  for(const video of videos){
      var elem = document.getElementById('app__videos');
      elem.addEventListener('scroll', function(){
        if(video.paused){
          video.play();
        }else{
          video.pause()
        }
      });
  }
}

loadVideos()

** Edit 2 per Dale, this detects all scrolling, not detecting the bottom of a video

function getScroll(){
  var elem = document.getElementById('app__videos');
  elem.sections = [...document.querySelectorAll('video')];
  elem.lastScrollTop = window.pageYOffset;

  elem.addEventListener('scroll', onScroll);

  function onScroll() {
    const scrollTop = elem.pageYOffset;

    const section = elem.sections
      .map(section => {
        const el = section;
        const rect = el.getBoundingClientRect();
        return {el, rect};
      })
      .find(section => section.rect.bottom >= (elem.innerHeight * 0.5));
      console.log("bottom of video")
    }
  }

getScroll()

** Edit 3 , I got it working to stop playing videos on scroll. I still cannot get the next video to start autoplaying without a user click though, If I try to autoplay it plays all videos not the current one in view.

function loadVideos(){
  
  var videos = document.querySelectorAll('video');
  
  for(const video of videos){
    let playAfterThisHeight = 500
    
    $('.app__videos').scroll(function() {
        if ($('.app__videos').scrollTop()> playAfterThisHeight) {
             video.pause()
        } else {

        }
    })
    
    video.addEventListener('click', function(){
        if(video.paused){
          video.play();
        }else{
          video.pause()
        }
     });
    
  }
}

loadVideos()

The CSS with snap-to

*{
  margin:0;
  box-sizing:border-box;
}

body{
  background:black;
  color:#fff;
  height:100vh;
  display:grid;
  place-items:center;
}

html{
  scroll-snap-type: y mandatory;
}

.app__videos{
  position:relative;
  height:750px;
  background:#fff;
  overflow:scroll;
  width:100%;
  max-width:400px;
  scroll-snap-type: y mandatory;
}

.app__videos:: webkit-scrollbar{
  display:none;
}

.app__videos{
  --ms-overflow-style:none;
  scrollbar-width:none;
}

.video{
  position:relative;
  width:100%;
  height:100%;
  background:#fff;
  scroll-snap-align:start;
}

.video__player{
  object-fit:cover;
  width:100%;
  height:100%;
}

Everything works great if I want the user to click to play and click to pause each video which isn't good obviously as they would have multiple videos playing if they forget to pause. So how can I change the click function to a autoplay and auto-pause based on the user scroll?

Ryan D
  • 741
  • 1
  • 11
  • 29
  • You have to add the `scroll` event listener to the element, which is being scrolled, not the video. – Geshode Sep 08 '22 at 00:48
  • Thanks I tried that, but all video splay only while scrolling which is weird. I posted the updated code above. – Ryan D Sep 08 '22 at 00:52
  • I'd use the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) and pause automatically. I wouldn't autoplay though, but that's me. – Heretic Monkey Sep 08 '22 at 00:53
  • You can add a scroll event listener that checks the video elements y axis in the window, when it scrolls off the page then pause the video, you can track the top and/or bottom position relative to the windows top/bottom – dale landry Sep 08 '22 at 00:54
  • @dalelandrycan you show an example of this please? When I try to add an event listener on app__videos it fires during all scroll events, cant get it to detect the bottom of a video. Im using - position.top >= 0 && position.bottom <= window.innerHeight – Ryan D Sep 08 '22 at 01:08
  • https://codepen.io/jonjamesdesign/pen/JBNGvQ you need to do something like here, fire events when you scroll from one to second and so on – Sonny49 Sep 08 '22 at 01:10
  • Thanks @Sonny49 but I cant get that to work with my use case. Its detecting the all of the user scrolling, not just the bottom of a video. Ill update the question with my implementation. – Ryan D Sep 08 '22 at 01:29
  • Yeah would be nice to provide some playground so people can jump on the problem and give you the answer faster. In the end of the this is just JS, not a complicated React or Vue project – Sonny49 Sep 08 '22 at 03:32
  • Yeah good idea, ill do that – Ryan D Sep 08 '22 at 03:36

0 Answers0