resizing an iFrame in a Vue component each time frame content changes

34 views Asked by At

I have a parent Vue component that renders an iframe which loads a child Vue component. When the user interacts with the child component it may load/reload another child component into the iframe.

I want to adjust the size of the iframe whenever it's content changes.

So I decided that when the current child hits the onMounted() hook it fires a signal to the parent (using postMessage).

The parent then queries the size of the document in the iframe and resizes the iframe to fit the content.

The problem I seem to be having is that the resize happens before the content is fully rendered, so the iframe is often the wrong size. If I set a 200 millisecond timeout it's fine.

Does this mean that onMounted() fires before the page is fully rendered? Any solutions to this?

The parent component:

<script setup>

import { usePostMessage }  from '@/composables/usePostMessage';
import { ref } from 'vue';

    const props = defineProps({
        src : {
            type : String,
            required : true
        },
        id : {
            type: String,
        }
    });

    const frame = ref(null);
    const isLoading = ref(true);

    const methods = {

        //adjust the iframe to fit the content
        resizeFrame(){
            const iframe = frame.value;
            if (iframe) {

                const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
                iframe.style.height = iframeDocument.body.offsetHeight + "px";
                console.log('iframe size: ' + iframe.style.height)

            }
        },
        onLoaded(){
            isLoading.value=false;
        }
    };

    //listen to events from the iframe
    const {  listenToPostMessage } = usePostMessage();

    listenToPostMessage(['mounted'],methods.onLoaded);
    listenToPostMessage(['resizeFrame'],methods.resizeFrame);

</script>

<template>

    <div v-if="isLoading">
        <slot name="loading" />
    </div>

    <iframe :src="src" ref="frame" class="w-full h-0" :id="id"></iframe>


</template>

In each child component:

    onMounted(() => {
        postMessageFromIframe({action:'resizeFrame'});

    });
0

There are 0 answers