[vue-pdf-embed@2] Lazy loading example

by hrynko

HTML

<script src="https://unpkg.com/vue@3.3.0/dist/vue.global.js"></script>
<script src="https://unpkg.com/vue-pdf-embed@2.1.0/dist/index.umd.js"></script>

<link rel="stylesheet" href="https://unpkg.com/vue-pdf-embed@2.1.0/dist/styles/annotationLayer.css">
<link rel="stylesheet" href="https://unpkg.com/vue-pdf-embed@2.1.0/dist/styles/textLayer.css">

<template id="appTemplate">
  <div class="app-content">
    <div v-for="pageNum in pageNums" :key="pageNum" ref="pageRefs">
      <vue-pdf-embed
        v-if="pageVisibility[pageNum]"
        :source="doc"
        :page="pageNum"
      />
    </div>
  </div>
</template>

<div id="app"></div>

CSS

body {
  margin: 0;
  padding: 0;
  background-color: #ccc;
}

.app-content {
  padding: 24px 16px;
}

.app-content > * {
  margin: 0 auto;
  padding-bottom: 8px;
}

.vue-pdf-embed__page {
  box-shadow: 0 2px 8px 4px rgba(0, 0, 0, 0.1);
}

JavaScript

Vue.createApp({
  template: document.getElementById('appTemplate').innerHTML,
  components: {
    'vue-pdf-embed': VuePdfEmbed,
  },
  setup() {
    const pageRefs = Vue.ref([])
    const pageVisibility = Vue.ref({})
    let pageIntersectionObserver

    const { doc } = useVuePdfEmbed({
    	source: 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf',
    })

    const pageNums = Vue.computed(() =>
    	doc.value
      	? [...Array(doc.value.numPages + 1).keys()].slice(1)
        : []
    )

    const resetPageIntersectionObserver = () => {
    	pageIntersectionObserver?.disconnect()
      pageIntersectionObserver = new IntersectionObserver((entries) => {
      	entries.forEach((entry) => {
        	if (entry.isIntersecting) {
          	const index = pageRefs.value.indexOf(entry.target)
            const pageNum = pageNums.value[index]
            pageVisibility.value[pageNum] = true
          }
        })
      })
      pageRefs.value.forEach((element) => {
      	pageIntersectionObserver.observe(element)
      })
    }

    Vue.watch(pageNums, (newPageNums) => {
      pageVisibility.value = { [newPageNums[0]]: true }
      Vue.nextTick(resetPageIntersectionObserver)
    })

    Vue.onBeforeUnmount(() => {
      pageIntersectionObserver?.disconnect()
    })

    return {
      doc,
      pageNums,
      pageRefs,
      pageVisibility,
    }
  },
}).mount('#app')