Skip to content

how load video only once if a modal is dynamic in vuejs3/vite?

I having a problem optimizing the performance of my application build in Vuejs3/Vite and Aframe. I need to somehow prefetch 6 videos. The problem is that each time I open a modal the browser fetches a video again. I want the browser to only fetch it once and store it somehow.

My application should look like this. Homepage has 6 buttons. On click, each button opens a modal. Inside the modal there a 6 videos. So, when a user clicks on the 2nd button the modal opens and inside it is only the 2nd video playing automatically. When a user clicks on a “close” button the modal is closed and the video is paused.

Right now my code looks like this: HTML template

// 6 button-images like this
<a-image
   class="link"
   src="/play-new.png"
   sound="on: click; src: #click-sound"
   @click="openVideo(0)"
   position="-5 1.5 -4.5"
   rotation="0 60 0"
></a-image>

// Modal
  <div
    v-show="isModalOpen"
    class=""

    <div v-for="(video, i) in videos" :key="i">
    <video :src="video.file" loop class="block" :class="i === currentVideo ? 'play' : 'hidden'" v-show="$nextTick(() => i === currentVideo && play(i))" />
     <div class="">
        <button @click="hideVideo" class="">X</button>
     </div>
    </div>
 </div>

My JS:

<script setup>

import { ref } from 'vue'

const videos = [ {
  file: 'videos/1.mp4',
},
{
  file: 'videos/2.mp4'
},
{
  file: 'videos/3.mp4'
},
{
  file: 'videos/4.mp4'
},
{
  file: 'videos/5.mp4'
},
{
  file: 'videos/6.mp4'
}
];

const currentVideo = ref(-1);

const isModalOpen = ref(false);

function openVideo(videoIndex) {
  currentVideo.value = videoIndex; //videos[videoIndex].file;
  isModalOpen.value = true;
}

function hideVideo() {
  document.querySelector('.play').pause();
  currentVideo.value = -1;
  isModalOpen.value = false;
}

function play(index) {
  if (index == currentVideo.value) {
    document.querySelector('.play').play();
    return true;
  } 
  return false;
}

</script>

Here what my network tab look like after I restart the page and open a modal. The initial load is red. The modal open is green. network tab

What I’ve tried so far: Instead of v-if I made it work with v-show because with v-if it is not fetched at all.

To sum it all up, how do I make a browser only load a video once and cache/store it.

Answer

Wrapping your component with <keep-alive> should work:

// Modal
  <div
    v-show="isModalOpen"
    class=""

    <div v-for="(video, i) in videos" :key="i">
    <keep-alive>
        <video :src="video.file" loop class="block" :class="i === currentVideo ? 'play' : 'hidden'" v-if="$nextTick(() => i === currentVideo && play(i))" />
    </keep-alive>
     <div class="">
        <button @click="hideVideo" class="">X</button>
     </div>
    </div>
 </div>

DOCS