TEXTBOOK SECTION / AI LEARNING

記事一覧ページを作成する

AI活用概論の「GASとmicroCMSで作るシンプルなポートフォリオ」より、記事一覧ページを作成するを解説。生成AI、AI活用、DX、業務改善を実践しながら学べるオンライン教材です。

4GASとmicroCMSで作るシンプルなポートフォリオ概論 / AI活用 / ChatGPT / Gemini / Claude / 基礎から学ぶ

OVERVIEW

この節で学べること

概要を表示する
項目内容
教材名AI活用概論
GASとmicroCMSで作るシンプルなポートフォリオ
記事一覧ページを作成する
カテゴリ概論 / AI活用 / ChatGPT / Gemini / Claude / 基礎から学ぶ
学習内容生成AI、AI活用、DX、業務改善を実践しながら理解するための教材です。

TABLE OF CONTENTS

目次

CONTENT

ここから

この節では、microCMSから取得した複数の記事を、Google Apps ScriptのHTMLテンプレートへ渡し、一覧ページとして表示します。

一覧ページでは、タイトル、概要、公開日、サムネイル画像をカード形式で並べます。


doGet(event)で表示するページを振り分ける

GASのWebアプリへアクセスすると、最初にdoGet(event)が実行されます。

function doGet(event) {
  const articleId = String(
    event?.parameter?.id ?? '',
  ).trim();

  if (articleId) {
    return renderDetailPage(articleId);
  }

  return renderIndexPage();
}

URLにidパラメータがあるかどうかで、表示するページを切り替えています。

idなし
→ 記事一覧ページ

idあり
→ 記事詳細ページ

一覧ページのURLは次の形式です。

<https://script.google.com/macros/s/デプロイID/exec>

記事詳細ページは、URLに記事IDを追加します。

<https://script.google.com/macros/s/デプロイID/exec?id=記事ID>

renderIndexPage()で一覧ページを作成する

記事一覧ページは、renderIndexPage()で生成します。

function renderIndexPage() {
  const template =
    HtmlService.createTemplateFromFile('index');

  template.articles = getArticles();

  return template
    .evaluate()
    .setTitle('ポートフォリオ')
    .addMetaTag(
      'viewport',
      'width=device-width, initial-scale=1',
    );
}

この関数では、次の処理を行っています。

  1. index.htmlをテンプレートとして読み込む
  2. microCMSから記事一覧を取得する
  3. 記事データをHTMLテンプレートへ渡す
  4. HTMLとして評価する
  5. ページタイトルと画面幅の設定を追加する

HTMLテンプレートへ記事データを渡す

microCMSから取得した記事一覧は、次のコードでHTMLへ渡します。

template.articles = getArticles();

getArticles()の戻り値は、複数の記事を含む配列です。

[
  {
    id: 'app-001',
    title: '受付管理アプリ',
    description: '受付状況を管理するアプリです。',
    thumbnail: {
      url: '<https://images.microcms-assets.io/>...'
    },
    publishedDate: '2026-07-13T00:00:00.000Z'
  }
]

index.htmlでは、articlesという変数名で利用できます。


index.htmlの基本構造

一覧ページは、次のような構造です。

<!doctype html>
<html lang="ja">
  <head>
    <base target="_top">
    <meta charset="UTF-8">
    <style>
      /* CSS */
    </style>
  </head>

  <body>
    <header>
      <!-- サイト名 -->
    </header>

    <main>
      <section>
        <!-- ページタイトル -->
      </section>

      <section>
        <!-- 記事一覧 -->
      </section>
    </main>
  </body>
</html>

<base target="_top">を指定すると、GASのHTML内にあるリンクをWebアプリ全体で開けます。

<base target="_top">

GASのテンプレート構文

GASのHTMLテンプレートでは、HTML内にJavaScriptの値や処理を埋め込めます。

値をHTMLへ出力する

<?= article.title ?>

<?= ?>は、値をHTMLへ表示するための構文です。

例えば、次のコードは記事タイトルを表示します。

<h2><?= article.title ?></h2>

JavaScriptの処理を実行する

<? if (articles.length === 0) { ?>
  <p>まだ記事がありません。</p>
<? } ?>

<? ?>は、条件分岐や繰り返しなどのJavaScript処理を記述する構文です。

この部分自体はHTMLへ表示されません。

HTMLをそのまま出力する

<?!= article.content ?>

<?!= ?>は、値をHTMLとしてそのまま出力する構文です。

主に、microCMSのリッチエディタ本文を表示するときに使用します。一覧ページでは通常使用しません。


articles.forEach()で記事を繰り返し表示する

複数の記事を一覧表示するには、forEach()を使用します。

<? articles.forEach(function(article) { ?>
  <article>
    <h2><?= article.title ?></h2>
    <p><?= article.description ?></p>
  </article>
<? }); ?>

記事が3件ある場合、<article>部分が3回繰り返されます。

今回のコードでは、カード全体をリンクにしています。

<? articles.forEach(function(article) { ?>
  <a
    class="article-card"
    href="<?= ScriptApp.getService().getUrl() ?>?id=<?= encodeURIComponent(article.id) ?>"
  >
    <!-- 記事内容 -->
  </a>
<? }); ?>

記事がない場合の表示

microCMSに公開済みの記事がない場合は、空のメッセージを表示します。

<? if (articles.length === 0) { ?>
  <div class="empty">
    まだ記事がありません。
  </div>
<? } ?>

この処理により、何も表示されない状態を防げます。


サムネイル画像を表示する

記事にサムネイル画像が登録されている場合は、画像を表示します。

<? if (article.thumbnail && article.thumbnail.url) { ?>
  <img
    class="thumbnail"
    src="<?= article.thumbnail.url ?>?w=640&h=360&fit=crop"
    alt="<?= article.title ?>"
    loading="lazy"
  >
<? } ?>

microCMSの画像URLへ、サイズ指定のパラメータを追加しています。

?w=640&h=360&fit=crop

それぞれの意味は次のとおりです。

パラメータ内容
w=640幅を640pxにする
h=360高さを360pxにする
fit=crop指定比率に合わせて切り抜く

640×360は、16:9の比率です。


画像がない場合の代替表示

サムネイル画像が登録されていない場合は、代替表示を出します。

<? } else { ?>
  <div class="thumbnail-placeholder">
    No Image
  </div>
<? } ?>

CSSで背景色と高さを設定すると、画像がなくてもカードのレイアウトが崩れません。

.thumbnail-placeholder {
  display: grid;
  min-height: 180px;
  place-items: center;
  background: #ecece8;
  color: #777777;
}

公開日を日本語形式に変換する

microCMSから取得する日時は、ISO形式です。

2026-07-13T00:00:00.000Z

そのままでは読みにくいため、formatDate()を使って日本語形式に変換します。

function formatDate(value) {
  const date = new Date(value);

  if (Number.isNaN(date.getTime())) {
    return '';
  }

  return Utilities.formatDate(
    date,
    'Asia/Tokyo',
    'yyyy年M月d日',
  );
}

HTML側では次のように呼び出します。

<p class="date">
  <?= formatDate(article.publishedDate) ?>
</p>

表示結果は次のようになります。

2026年7月13日

記事詳細ページへのリンクを作成する

記事カードをクリックしたときに詳細ページへ移動するため、記事IDをURLへ追加します。

href="<?= ScriptApp.getService().getUrl() ?>?id=<?= encodeURIComponent(article.id) ?>"

ScriptApp.getService().getUrl()は、現在のWebアプリURLを取得します。

生成されるURLは次のような形式です。

<https://script.google.com/macros/s/デプロイID/exec?id=app-001>

encodeURIComponent()を使うことで、記事IDをURLへ安全に追加できます。


記事カードのHTML

記事カード全体は、次の構成です。

<a
  class="article-card"
  href="<?= ScriptApp.getService().getUrl() ?>?id=<?= encodeURIComponent(article.id) ?>"
>
  <? if (article.thumbnail && article.thumbnail.url) { ?>
    <img
      class="thumbnail"
      src="<?= article.thumbnail.url ?>?w=640&h=360&fit=crop"
      alt="<?= article.title ?>"
      loading="lazy"
    >
  <? } else { ?>
    <div class="thumbnail-placeholder">
      No Image
    </div>
  <? } ?>

  <div class="content">
    <p class="date">
      <?= formatDate(article.publishedDate) ?>
    </p>

    <h2><?= article.title ?></h2>

    <p class="description">
      <?= article.description ?>
    </p>
  </div>
</a>

カード全体を<a>タグにすることで、どこをクリックしても詳細ページへ移動できます。


CSS Gridでカードを配置する

記事カードでは、画像と文章を横並びにしています。

.article-card {
  display: grid;
  grid-template-columns: 240px 1fr;
  overflow: hidden;
  border: 1px solid #ddddda;
  border-radius: 16px;
  background: #ffffff;
  text-decoration: none;
}

次の指定により、2列のレイアウトになります。

grid-template-columns: 240px 1fr;

左側は240pxの画像領域、右側は残りの横幅を使う文章領域です。


複数のカードを縦に並べる

記事一覧全体にもCSS Gridを使用します。

.articles {
  display: grid;
  gap: 24px;
  padding-bottom: 96px;
}

gap: 24pxによって、カード同士の間に余白を作ります。


サムネイル画像を整える

サムネイルには次のCSSを指定します。

.thumbnail {
  width: 100%;
  height: 100%;
  min-height: 180px;
  object-fit: cover;
  background: #ecece8;
}

object-fit: coverを使用すると、画像の縦横比が異なっていても、領域全体を埋めるように表示できます。

画像の一部が切り取られる場合がありますが、カードの大きさは揃います。


スマートフォン表示へ対応する

画面幅が680px以下の場合、画像と文章を縦並びにします。

@media (max-width: 680px) {
  .article-card {
    grid-template-columns: 1fr;
  }

  .thumbnail {
    aspect-ratio: 16 / 9;
  }
}

PCでは横並びです。

画像|タイトル・概要

スマートフォンでは縦並びになります。

画像
タイトル・概要

aspect-ratio: 16 / 9を指定することで、スマートフォンでもサムネイルを一定の比率で表示できます。


一覧ページの処理の流れ

一覧ページが表示されるまでの流れは次のとおりです。

ブラウザからWebアプリへアクセス
  ↓
doGet(event)
  ↓
idパラメータがないことを確認
  ↓
renderIndexPage()
  ↓
getArticles()
  ↓
microCMSから記事一覧を取得
  ↓
template.articlesへ代入
  ↓
index.htmlをevaluate()
  ↓
articles.forEach()でカードを生成
  ↓
ブラウザへ一覧ページを返す

到達目標

この節では、microCMSから取得した記事一覧をGASのHTMLテンプレートへ渡し、articles.forEach()を使って複数の記事を表示できることを目標とします。

また、サムネイル画像、公開日、記事詳細へのリンクを含むカードを作成し、CSS Gridとメディアクエリを使って、PCとスマートフォンの両方に対応した一覧ページを作成できるようになります。

次ページ

https://app.notion.com/p/Web-332b4ab5d13681c0a24dde460b8938e5?v=2c7b4ab5d136802d9a64000c46ee24e8&source=copy_link

FAQ

よくある質問

記事一覧ページを作成するは医療関係者向けだけの内容ですか。
医療分野の例が含まれる場合もありますが、医療関係者だけに限定した内容ではありません。生成AI、AI活用、DX、業務改善、プロトタイプ開発など、一般的なAI学習の事例として読める内容です。
AI初心者でも読めますか。
はい。AIをこれから学ぶ方、数学が苦手な方、仕事でAIを使いたい方にも読み進めやすいように、教材の章と節の流れに沿って整理しています。
サムネイル画像は必ず表示されますか。
はい。教材にcoverUrlが設定されている場合はその画像を表示し、未設定の場合は代替サムネイル画像を表示します。
AI活用概論のほかの章も読めますか。
はい。教材トップから章立てを確認でき、前後の節へもページ下部のナビゲーションから移動できます。