cirry

cirry

我的原生博客地址:https://cirry.cn

Astroで画像の遅延読み込みを実現する

考え方#

画像の遅延読み込みの方法は、Intersection Observer APIを使用して非常に簡単に実装できます。

しかし、Astro での実装は異なります。なぜなら、ここで実現するのはウェブサイト上の画像の遅延読み込みではなく、ブログ内の画像の遅延読み込みです。

Astro のブログは Markdown で書かれており、Frontmatter にlayoutを追加してレンダリングするコンポーネントを指定します。ブログを開くときには、コンポーネントがすでに読み込まれています。ブログの中の image タグにはすでに src 属性があり、データを取得するためにリクエストが送信されています。

最初の考えは、ページを開いた後、画像がリクエストを送信する前に、image の src 属性を削除して data-src に保存するフック関数を見つけることでした。window.onloadよりも早いフック関数があれば良いのですが、そのような方法はありませんでした。

そのため、markdown を html にレンダリングする際に、image タグを処理することにしました。このアイデアは実現可能だと思われるため、Astro のドキュメントを見てみると、markdown.remarkPluginsという設定方法が見つかりました。

公式ウェブサイトの手がかりに従って、GitHub で検索していると、このパッケージを見つけました:remarkjs/remark。このパッケージには、h タグのレベルを 1 つ下げるコード例があります。つまり、h2 タグが h3 タグに変わります。

import { visit } from 'unist-util-visit'

function myRemarkPluginToIncreaseHeadings() {
  return (tree) => {
    visit(tree, (node) => {
      if (node.type === 'heading') {
        node.depth++
      }
    })
  }
}

元の md ドキュメント:

# Hi, Saturn!

ページの html は:

<h1>Hi, Saturn</h1>

フォーマット後、ページの html は:

<h2>Hi, Saturn</h2>

上記の例から、このプラグインが要件を満たすことがわかりましたので、実装を始めます。

実装#

astro.config.mjsに以下のコードを追加します:

import { visit } from 'unist-util-visit'

function myRemarkPluginToLazyLoadImage() {
  return (tree) => {
    visit(tree, (node) => {
      if (node.type === 'image') {
        // url属性をaltに設定し、さらにurlを空にすることで、ページの読み込み時にurl属性がないため画像が読み込まれなくなります
        node.alt = node.url 
        node.url = ''
      }
    })
  }
}

export default defineConfig({
  ..., // 他の設定
  markdown: {
    remarkPlugins: [myRemarkPluginToLazyLoadImage],
    // これを追加しないと、mdをhtmlに変換せず、プラグイン内のコードのみを処理します
    extendDefaultPlugins: true, 
  }
})

md をインポートする Astro コンポーネントに以下のコードを追加します:

<script>
/* ブログ内のすべてのimgタグを検索します */
var markdownBody = document.querySelector(".markdown-body");
let images = markdownBody.querySelectorAll("img");

const callback = (entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const image = entry.target;
      const data_src = image.getAttribute("alt");
      image.setAttribute("src", data_src);
      observer.unobserve(image);
      }
    });
  };
/* 各imgタグに監視メソッドを追加します */
  const observer = new IntersectionObserver(callback);
  images.forEach((image) => {
    observer.observe(image);
  });
}
</script>

これで、画像の遅延読み込みが完了しました!

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。