skip to content
Logo
Yurikago Blog

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で画像を遅延読み込みする際はこのモジュールを利用するだけで事足りそうですね👍

参考: https://github.com/nuxt/image