1. Demand background

Some time ago, we received a demand that the operation hoped that the H5 page could realize the automatic playback of the video when it enters the field of view, just like the following:

This can endure, can not endure how to do, who let her is the demand side. Because there are many video pits, many WebViews do not support automatic playback, and there are so many kinds of Android devices. Even if it is implemented by hack, it cannot guarantee that all devices are compatible.

Finally, a compromise scheme is adopted: video automatically plays when entering the viewport (because webViews at both ends support automatic play) is supported in the end, but not outside the end.

2. Implement

Of course, the most convenient way to implement this feature is to use IntersectionObserver. Let’s take a look at the API compatibility:

Compatibility is not very good, the production environment still need to introduce polyfill: github.com/w3c/Interse…

IntersectionObserver

IntersectionObserver can be used to judge whether an element has entered the “viewport”. So we can execute our callback function after the element enters the viewport.

If you are not familiar with this API, you can follow the course of IntersectionObserver API by Yifeng Ruan.

Train of thought

  • First, we need to monitor every module.
  • When the module is fully in the viewport, let the module insidevideoPlay.

Open dry

The HTML and CSS code for demo is as follows:

<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, user - scalable = no, initial - scale = 1.0">
  <title>Document</title>
  <style>
    * {
      padding: 0;
      margin: 0;
      box-sizing: border-box;
    }

    html.body {
      font-size: 100px;
      padding:.1rem;
      overflow-x: hidden;
      background: linear-gradient(thistle, wheat);
    }

    .title {
      font-size:.22rem;
      margin: 50px auto;
      color: seagreen;
      text-align: center;
      border:.02rem dashed sienna;
    }

    .video-box {
      width: 100%;
      height: 4rem;
      border:.04rem solid;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      margin-bottom:.5rem;
    }

    .one {
      border-color: seagreen;
    }

    .two {
      border-color: skyblue;
    }

    .three {
      border-color: thistle;
    }

    .four {
      border-color: tomato;
    }

    .five {
      border-color: rosybrown;
    }

    .video-box>p {
      font-size:.2rem;
      color: sienna;
      margin-bottom:.2rem;
    }

    video {
      width: 2.8 rem;
      height: 1.8 rem;
      border-radius:.1rem;
      object-fit: cover;
    }
  </style>

</head>

<body>
  <h2 class="title">H5 When a video enters the viewport, the Demo is played automatically</h2>
  <section class="video-box one">
    <p>A module</p>
    <video
      controls
      loop="loop"
      x5-playsinline
      playsinline="true"
      x-webkit-airplay="allow"
      webkit-playsinline="true"
      x5-video-player-type="h5"
      x5-video-player-fullscreen="true"
      poster="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg"
      src="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4"
    ></video>
  </section>
  <section class="video-box two">
    <p>Module 2</p>
    <video
      controls
      loop="loop"
      x5-playsinline
      playsinline="true"
      x-webkit-airplay="allow"
      webkit-playsinline="true"
      x5-video-player-type="h5"
      x5-video-player-fullscreen="true"
      poster="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg"
      src="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4"
    ></video>
  </section>
  <section class="video-box three">
    <p>Module 3</p>
    <video
      controls
      loop="loop"
      x5-playsinline
      playsinline="true"
      x-webkit-airplay="allow"
      webkit-playsinline="true"
      x5-video-player-type="h5"
      x5-video-player-fullscreen="true"
      poster="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg"
      src="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4"
    ></video>
  </section>
  <section class="video-box four">
    <p>Four modules</p>
    <video
      controls
      loop="loop"
      x5-playsinline
      playsinline="true"
      x-webkit-airplay="allow"
      webkit-playsinline="true"
      x5-video-player-type="h5"
      x5-video-player-fullscreen="true"
      poster="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg"
      src="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4"
    ></video>
  </section>
  <section class="video-box five">
    <p>Module five</p>
    <video
      controls
      loop="loop"
      x5-playsinline
      playsinline="true"
      x-webkit-airplay="allow"
      webkit-playsinline="true"
      x5-video-player-type="h5"
      x5-video-player-fullscreen="true"
      poster="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg"
      src="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4"
    ></video>
  </section>
</body>
</html> 
Copy the code

In order to simulate the effect of auto-playing in the viewport, the page has five video modules in total:

The following needs to fill js, complete the finishing touch:

  • Listen on all modules, i.evideo-boxClass:
  function arrayLikeToArray(arrayLike) {
    return Array.from(arrayLike);
  };

  const sectionList = arrayLikeToArray(document.querySelectorAll('.video-box'));
  
  // Listen on all module Dom
  const elementsObserve = new IntersectionObserver(entries= > {
    entries.forEach(item= > {
      // If the module appears in the viewport
      if (item.isIntersecting) {
        const video = item.target.getElementsByTagName('video') [0]; video.play(); }})}, {// Trigger the above callback when the currently monitored element is completely in the viewport: play the video in the module
    threshold: [1]}); sectionList.forEach(item= > {
    elementsObserve.observe(item);
  });
Copy the code

After completing the above code, the video can be automatically played after appearing in the viewport. However, the above code may cause multiple videos to be played at the same time on the page (restrictions for simultaneous video playing in different browsers/WebViews are different).

  • Only one video can be played at a time
  // +
  const videoList = arrayLikeToArray(document.querySelectorAll('video'));
  function onlyOneVideoCanPlay(video) {
    videoList.forEach(item= > {
      if (item === video) {
        item.play();
      } else{ item.pause(); }})}function arrayLikeToArray(arrayLike) {
    return Array.from(arrayLike);
  };

  const sectionList = arrayLikeToArray(document.querySelectorAll('.video-box'));
  const elementsObserve = new IntersectionObserver(entries= > {
    entries.forEach(item= > {
      if (item.isIntersecting) {
        const video = item.target.getElementsByTagName('video') [0];
        // -onlyOneVideoCanPlay(video); }})}, {threshold: [1]}); sectionList.forEach(item= > {
    elementsObserve.observe(item);
  });
Copy the code

Effect:

In Chrome, you need to manually click to play a video and then swipe.

The complete code

<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="Width = device - width, user - scalable = no, initial - scale = 1.0">
  <title>Document</title>
  <style>
    * {
      padding: 0;
      margin: 0;
      box-sizing: border-box;
    }

    html.body {
      font-size: 100px;
      padding:.1rem;
      overflow-x: hidden;
      background: linear-gradient(thistle, wheat);
    }

    .title {
      font-size:.22rem;
      margin: 50px auto;
      color: seagreen;
      text-align: center;
      border:.02rem dashed sienna;
    }

    .video-box {
      width: 100%;
      height: 4rem;
      border:.04rem solid;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      margin-bottom:.5rem;
    }

    .one {
      border-color: seagreen;
    }

    .two {
      border-color: skyblue;
    }

    .three {
      border-color: thistle;
    }

    .four {
      border-color: tomato;
    }

    .five {
      border-color: rosybrown;
    }

    .video-box>p {
      font-size:.2rem;
      color: sienna;
      margin-bottom:.2rem;
    }

    video {
      width: 2.8 rem;
      height: 1.8 rem;
      border-radius:.1rem;
      object-fit: cover;
    }
  </style>

</head>

<body>
  <h2 class="title">H5 When a video enters the viewport, the Demo is played automatically</h2>
  <section class="video-box one">
    <p>A module</p>
    <video
      controls
      loop="loop"
      x5-playsinline
      playsinline="true"
      x-webkit-airplay="allow"
      webkit-playsinline="true"
      x5-video-player-type="h5"
      x5-video-player-fullscreen="true"
      poster="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg"
      src="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4"
    ></video>
  </section>
  <section class="video-box two">
    <p>Module 2</p>
    <video
      controls
      loop="loop"
      x5-playsinline
      playsinline="true"
      x-webkit-airplay="allow"
      webkit-playsinline="true"
      x5-video-player-type="h5"
      x5-video-player-fullscreen="true"
      poster="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg"
      src="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4"
    ></video>
  </section>
  <section class="video-box three">
    <p>Module 3</p>
    <video
      controls
      loop="loop"
      x5-playsinline
      playsinline="true"
      x-webkit-airplay="allow"
      webkit-playsinline="true"
      x5-video-player-type="h5"
      x5-video-player-fullscreen="true"
      poster="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg"
      src="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4"
    ></video>
  </section>
  <section class="video-box four">
    <p>Four modules</p>
    <video
      controls
      loop="loop"
      x5-playsinline
      playsinline="true"
      x-webkit-airplay="allow"
      webkit-playsinline="true"
      x5-video-player-type="h5"
      x5-video-player-fullscreen="true"
      poster="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg"
      src="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4"
    ></video>
  </section>
  <section class="video-box five">
    <p>Module five</p>
    <video
      controls
      loop="loop"
      x5-playsinline
      playsinline="true"
      x-webkit-airplay="allow"
      webkit-playsinline="true"
      x5-video-player-type="h5"
      x5-video-player-fullscreen="true"
      poster="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg"
      src="https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/xgplayer-demo-720p.mp4"
    ></video>
  </section>
</body>

<script>
  function arrayLikeToArray(arrayLike) {
    return Array.from(arrayLike);
  }
  function commonIntersection(elements, cb) {
    const elementsObserve = new IntersectionObserver(entries= > {
      entries.forEach(item= > {
        if(item.isIntersecting) { cb(item); }})}, {threshold: [1]});if (Array.isArray(elements)) {
      elements.forEach(item= >{ elementsObserve.observe(item); })}else{ elementsObserve.observe(elements); }}function setVideoAutoPlay() {
    // The video appears in the middle of the screen and plays automatically
    const sectionList = arrayLikeToArray(document.querySelectorAll('.video-box'));
    commonIntersection(sectionList, item= > {
      const video = item.target.getElementsByTagName('video') [0];
      onlyOneVideoCanPlay(video);
    });
  }

  const videoList = arrayLikeToArray(document.querySelectorAll('video'));
  function onlyOneVideoCanPlay(video) {
    videoList.forEach(item= > {
      if (item === video) {
        item.play();
      } else {
        item.pause();
      }
    })
  }

  setVideoAutoPlay();
</script>

</html> 
Copy the code

3. Reference links

  • IntersectionObserver API Usage Tutorial – Ruan Yifeng
  • IntersectionObserver Polyfill