Search code examples
vue.jseventsvideo.jsrefv-for

How to use single button to play/stop multiple video child elements created by v-for in Vuejs?


I need to show multiple video files playing at same time.

so I have this code:

<b-row class="justify-content-md-center">
        <b-col>
          <li v-for="(video, index) in videoArray" :key='(video, index)'>
            <video 
            v-if=" index % 2 == 0 " 
            :ref="videoPlayer" 
            @canplay="updatePaused"
            @playing="updatePaused"
            @pause="updatePaused"
            class="video-js vjs-custom-skin vjs-16-9"
            controls autoplay loop preload="auto"
            data-setup='{}'>
              <source v-bind:src="require(`./storage/${video}`)" type="video/mp4">
            </video>
          </li>
        </b-col>
        <b-col>
          <li v-for="(video, index) in videoArray" :key='(video, index)'>
            <video 
            v-if=" (index+1) % 2 == 0 "
            :ref="`videoPlayer${index}`" 
            @canplay="updatePaused"
            @playing="updatePaused"
            @pause="updatePaused"
            class="video-js vjs-custom-skin vjs-16-9"
            controls autoplay loop preload="auto"
            data-setup='{}'>
              <source v-bind:src="require(`./storage/${video}`)" type="video/mp4">
            </video>
          </li>
        </b-col>

 <div id="button">
      </b-row>
        <b-row class="justify-content-md-center">
      <b-button @click="generalPlay" :pressed.sync="playStatus" variant="outline-light">Play All</b-button>
      <b-button @click="stopPlay" :pressed.sync="playStatus" variant="outline-light">Stop All</b-button>
        </b-row>
 </div>

Video player intends to read data from data storage and play, as you can see, the player can read the video files and be ready, but I couldn't use single button to play all of them or pause all of them. When I tried to work it out, I realized I couldn't use button to trigger each element created by v-for, so I focus on how to pause all the files at same time.

I tried:

  1. event.target

as shown, I added @canplay="updatePaused", @playing="updatePaused", @pause="updatePaused", and mount loop as well as corresponding method, it worked, but only for the last file, I can merely stop single video file playing.

  1. $ref

then I use $ref, even tried to read index of v-for, see whether it worked, but still fail.

export default {
  name: 'player',
  data () {
    return {
        videoElement: null, 
        videoArray: [],
    }
  },
  mounted () {
    let count = storageList.length;
    while (count--) {
      if(storageList[count].type == "video") {
        this.videoArray.push(storageList[count].filename);
        //storageList is data storage file
      }
    }
  },
methods: {
    /*
    updatePaused(event) { 
      this.videoElement = event.target;
    },
    */
    stopPlay: () => {
      for( let index in this.videoArray ) {      
        videojs(this.$refs[`videoPlayer${index}`]).pause();
      //ideojs(this.$refs.videoPlayer).pause()
      //videojs(this.videoElement).pause(); 
      }
    }

  },
}

I really don't know what I can do for this with my limited experience and knowledge of Vuejs, could anyone help me out here? Thanks !!


Solution

  • From what I understood you want to write the generalPlay and stopPlay methods.

    It might be easier to query the video elements and stop them instead of storing their references.

    stopPlay: () => {
      let videoElements = this.$el.querySelectorAll('video')
      for (let i = 0; i < videoElements.length; i++) {
        videoElements[i].pause() // or videojs(videoElements[i]).pause()
      }
    }
    

    And then do the same for the play but with videoElements[i].play() instead.

    I don't quite know the videojs API, but an approach like this should work.