Search code examples
typescriptvuejs2vuejs3jspdfhtml2canvas

Html2canvas, but text disappeared


Use html2canvas to convert html to canvas, but the text in the exported result disappears

<template>
    <div>
        <div id="exam">
            <h2>文本 Example</h2>
            <p>example example example example example example</p>
        </div>

        <br/><br/>
        <button @click="output">Print</button><br/><br/><br/>

        <p>Result:</p><br/>
        <div id="res"></div>
    </div>
</template>

<script lang="ts" setup>
import html2canvas from 'html2canvas'
const output = async () => {
    const dom = document.getElementById('exam')
    if (dom) {
        const cvs = await html2canvas(dom)
        document.getElementById('res')?.append(cvs)
    }
}
</script>

export result

html2canvas + vue3 + ts + sass.


Solution

  • I wonder how often I see developers using getElementById or querySelector in vue components. You should make sure to use so called template refs.

    You might try the following approach (which I didn’t test, but something like this should work).

    <div>
      <div ref="exam">
        <h2>文本 Example</h2>
        <p>example example example example example example</p>
      </div>
      <div ref="result"></div>
    </div>
    
    // inside script setup
    import html2canvas from 'html2canvas'
    
    const exam = ref<HTMLDivElement | null>(null);
    const result = ref<HTMLDivElement | null>(null);
    const cvs = ref<??? | undefined>();
    
    const output = async () => {
      if (!exam.value || !result.value) return;
      
      // saving the cvs value in a ref variable
      // to keep it available on rerenderings.
      cvs.value = await html2canvas(exam.value)
    }
    
    // add a watcher that append the result
    // in order to apply it every time the
    // something changes because vue will
    // empty the element each time you update something.
    watch(
      cvs,
      (newCvs) => {
        if (!newCvs || !result.value) return;
        // clean the result element
        result.value.innerHTML = '';
    
        // append the new created cvs
        result.value.append(newCvs);
      },
      { flush: 'post' },
    )