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:
