Nuxt+TypeScript環境で画像を遅延読み込みする(Intersection Observer編)
/ 4 min read
Table of Contents
以下の検証環境でIntersection Observerを使って画像を遅延読み込みする方法をまとめました。
Vue製のIntersection Observerコンポーネントを提供するパッケージ (vue-intersect) はすでに存在しますが、このコンポーネントを検証環境で使おうとしたところ以下のエラーが発生しました。
SyntaxError Cannot use import statement outside a module
参考: https://github.com/heavyy/vue-intersect
また、以下の記事の対応方法を試してみましたが以下の新たなエラーが発生したため、検証環境で動作するIntersection Observerコンポーネントを作成しました。
Error render function or template not defined in component: Intersect
参考: https://zenn.dev/sengosha/articles/63a04ba5da5303e3993d
検証環境
- package.json
- nuxt v2.14.6
- @nuxtjs/composition-api v0.15.0
- @nuxt/typescript-build v2.0.3
検証リポジトリ: https://github.com/cuavv/sandbox-nuxt-intersection-observer
挙動について
- 遅延読み込みさせたい要素をObserverコンポーネントのスロットに渡します。サンプルではthresholdに[0.2, 0.8]を設定しており、ブラウザのビューポートと画像要素の交差率が0.2または0.8を上回ったり下回ったりしたときにonEnterやonLeave関数が実行されます。
- 遅延読み込み前はsrc属性に設定したダミー画像が表示され、onEnterが実行されるタイミングでsrcの値をdata-srcの値で書き換えます。
- rootやrootMarginなど、threshold以外のオプションを設定することもできます。
- サンプルではimgタグを記述しましたが、例えばiframeやdivなどの要素であっても監視対象にできるので、Observerコンポーネントのイベントハンドラーに設定する関数を編集すれば任意の処理を遅延実行できます。
<template> <Observer :threshold="[0.2, 0.8]" @enter="onEnter" @leave="onLeave" @change="onChange" > <img ref="lazyImageRef" src="/images/dummy.png" :data-src="src" :height="height" :width="width" :alt="alt" :title="title" /> </Observer></template>
<script lang="ts">import { defineComponent, ref } from '@nuxtjs/composition-api'// TODO: Polyfill
export default defineComponent({ props: { src: { type: String, required: true, }, height: { type: String, required: false, }, width: { type: String, required: false, }, alt: { type: String, required: false, }, title: { type: String, required: false, }, }, setup() { const lazyImageRef = ref<HTMLImageElement>() return { lazyImageRef, } }, methods: { onEnter() { if (!this.lazyImageRef) return console.log('onEnter')
if (this.lazyImageRef.dataset.src) { this.lazyImageRef.src = this.lazyImageRef.dataset.src delete this.lazyImageRef.dataset.src } }, onLeave() { console.log('onLeave') }, onChange() { console.log('onChange') }, },})</script>
補足: IE対応について
Intersection Obserber APIはIEで対応されていないので利用する際はPolyfillを導入してください。
参考: https://github.com/w3c/IntersectionObserver/tree/master/polyfill
補足: nuxt/imageについて
この記事を作成したあとに知ったのですが、Nuxt向けに最適化された画像コンポーネントを提供するモジュールとしてnuxt/imageがあります。
主な特徴として「遅延読み込み」「完全な静的サポート」「CDNサポート」を備えています。また、このモジュールを利用するとNuxtは画像のアスペクト比を自動的に計算し、アスペクト比に基づいて画像のサイズを設定します。アスペクト比を維持するように画像を強制するとレイアウトのシフトが防止されるため、Core Web VitalsのCLSを低いスコアに抑えられそうです。
Nuxtで画像を遅延読み込みする際はこのモジュールを利用するだけで事足りそうですね👍