Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass an Iframe to different Components in an SPA (similar to Youtube)

So since some time Youtube has the functionality to minimize the Youtube Player while navigating through the page, LolEsports.com has a similar functionality with Twitch and the Embeded Youtube Player.

I wanna bring a similar functionaltiy to my page basicly my state looks like this:

  • Vue in the Frontend
  • Embdeded Youtube Player on a suburl
  • When I leave the suburl I want the Youtube Player to move into a corner with its current state and still be there

I would like to hear some inspiration on how I could achieve that since when I tried out the state reset when passing it on a different component and also the playing stopped etc.

Would love to hear ideas

like image 904
Badgy Avatar asked Nov 15 '25 00:11

Badgy


1 Answers

The short answer is: You cannot move iframe DOM nodes without losing its state, as outlined in this answer.

The long answer is: You have alternatives. I think your best bet is to play the video directly in the "corner player", then restyle it to be on the right place of the page. To do so you will need to interact with the DOM yourself a bit, which you can do easily by setting a ref on the container you want the video to appear in.

In the end you would end up with something like this:

In your App.vue you have your standard router-view, as well as some element that will contain your actual video.

<template>
  <div id="app">
    <router-view/>
    <corner-player/>
  </div>
</template>

Your page that will start the video will contain some placeholder element that will serve as a guiding point where to put the video:

<div class="player-container" ref="player"></div>

We then use lifecycle hooks to get the correct url and styling to send to the player. I use a simple bus to more easily pass events around the application, as it would generally be a hassle to get the data to the player component otherwise. We use the mounted hook to set up the video, because that is when the first render cycle has taken place. The beforeDestroy lifecycle allows us to send some kind of event that will put the video in the corner.

export default {
  name: "child1",

  mounted() {
    const container = this.$refs.player;
    const boundingBox = container.getBoundingClientRect();

    this.$bus.$emit("play-video", {
      url: "https://www.youtube.com/embed/dW4HCi1zZh8",
      styling: {
        position: "absolute",
        top: `${boundingBox.top}px`,
        left: `${boundingBox.left}px`,
        width: `${boundingBox.width}px`,
        height: `${boundingBox.height}px`,
        border: "3px dotted red"
      }
    });
  },

  beforeDestroy() {
    this.$bus.$emit("move-to-corner-player");
  }
};

The player component then consumes these two events and makes sure that the correct styling is applied. I would not recommend applying raw css like I do here, but this is a proof of concept.

<template>
  <div class="corner-player" :style="styling" v-if="url">
    <iframe
      width="1280"
      height="540"
      :src="url"
      frameborder="0"
      allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
      allowfullscreen
    ></iframe>
  </div>
</template>

<script>
export default {
  name: "CornerPlayer",

  data() {
    return {
      styling: {},
      url: "",

      defaultStyling: {
        border: "3px solid blue",
        position: "fixed",
        bottom: 0,
        right: 0,
        height: "150px",
        width: "220px"
      }
    };
  },

  created() {
    this.$bus.$on("play-video", this.playVideo);
    this.$bus.$on("move-to-corner-player", this.moveToCornerPlayer);
  },

  beforeDestroy() {
    // Prevent memory leaks
    this.$bus.$off("play-video", this.playVideo);
    this.$bus.$off("move-to-corner-player", this.moveToCornerPlayer);
  },

  methods: {
    playVideo({ url, styling }) {
      this.url = url;
      this.styling = styling;
    },

    moveToCornerPlayer() {
      this.styling = {
        ...this.defaultStyling
      };
    }
  }
};
</script>

<style scoped>
iframe {
  width: 100%;
  height: 100%;
}
</style>

You can play with this on Codesandbox:

Edit Pass an Iframe to different Components in an SPA (similar to Youtube)

like image 162
Sumurai8 Avatar answered Nov 17 '25 17:11

Sumurai8



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!