コンテンツにスキップ

初めてのスクリプトをブラウザに送信する

クライアントサイドのインタラクションを必要とするような、モバイルの画面サイズでナビゲーションメニューを開閉するボタンを追加しましょう!

ここで学ぶことは...

  • メニューコンポーネントを作成する
  • サイト訪問者がナビゲーションメニューを開閉できるように<script>を書く
  • JavaScriptを.jsファイルに移動する

メニューコンポーネントを作成する

モバイルメニューを開閉する<Menu />コンポーネントを作成します。

  1. src/components/Menu.astroという名前のファイルを作成します。

  2. 以下のコードをコンポーネントにコピーします。これは、モバイルデバイスでナビゲーションリンクを開閉するボタンを作成します。(あとでglobal.cssに新しいCSSスタイルを追加します。)

    --- 
    ---
    <button aria-expanded="false" aria-controls="main-menu" class="menu">
      Menu
    </button>
  3. Header.astro<Navigation />コンポーネントの直前に、新しい<Menu />コンポーネントを配置します。

    コードを表示

    ---
    import Menu from './Menu.astro';
    import Navigation from './Navigation.astro';
    ---
    <header>
      <nav>
        <Menu />
        <Navigation />
      </nav>
    </header>
  4. レスポンシブなスタイルを含む以下のメニューコンポーネント用スタイルを追加します。

    /* ナビゲーションのスタイル */
    .menu {
      background-color: #0d0950;
      border: none;
      color: #fff;
      font-size: 1.2rem;
      font-weight: bold;
      padding: 5px 10px;
    }
    
    .nav-links {
      width: 100%;
      display: none;
      margin: 0;
    }
    
    .nav-links a {
      display: block;
      text-align: center;
      padding: 10px 0;
      text-decoration: none;
      font-size: 1.2rem;
      font-weight: bold;
      text-transform: uppercase;
      color: #0d0950;
    }
    
    .nav-links a:hover,
    .nav-links a:focus{
      background-color: #ff9776;
    }
    
    :has(.menu[aria-expanded="true"]) .nav-links {
      display: unset;
    }
    
    @media screen and (min-width: 636px) {
      .nav-links {
        margin-left: 5em;
        display: block;
        position: static;
        width: auto;
        background: none;
      }
    
      .nav-links a {
        display: inline-block;
        padding: 15px 20px;
      }
    
      .menu {
        display: none;
      }
    }

初めてのスクリプトタグを書く

ヘッダーはまだインタラクティブではありません。メニューへのクリックに応じてナビゲーションリンクを表示したり非表示にしたりするように、ユーザーの入力に応答することができないからです。

<script>タグを追加すると、クライアントサイドのJavaScriptがユーザーのイベントを「待ち受け(Listen)」、それに応答します。

  1. index.astro</body>閉じタグの直前に、Astro組み込みのTypeScriptサポートを利用して以下の<script>タグを追加します。

      <Footer />
      <script>
        const menu = document.querySelector('.menu');
    
        menu?.addEventListener('click', () => {
          const isExpanded = menu.getAttribute('aria-expanded') === 'true';
          menu.setAttribute('aria-expanded', `${!isExpanded}`);
        });
      </script>
    </body>
  2. ブラウザのプレビューを複数のサイズで開き、このページのナビゲーションメニューがスクリーンサイズに対してレスポンシブであり、またユーザーの入力に反応することを確認します。

.jsファイルをインポートする

各ページにJavaScriptを直接書く代わりに、<script>タグの内容をプロジェクト内の.jsファイルに移動しましょう。

  1. (新しく/scripts/フォルダを作成した上で)src/scripts/menu.jsを作成し、JavaScriptをそこに移動します。

    const menu = document.querySelector('.menu');
    
    menu?.addEventListener('click', () => {
      const isExpanded = menu.getAttribute('aria-expanded') === 'true';
      menu.setAttribute('aria-expanded', `${!isExpanded}`);
    });
  2. index.astro<script>タグの内容を以下のファイルインポートに置き換えます。

      <Footer />
      <script>
        const menu = document.querySelector('.menu');
    
        menu?.addEventListener('click', () => {
          const isExpanded = menu.getAttribute('aria-expanded') === 'true';
          menu.setAttribute('aria-expanded', `${!isExpanded}`);
        });
    
        import "../scripts/menu.js";
      </script>
    </body>
  3. ブラウザのプレビューを再度小さいサイズで開き、メニューがナビゲーションリンクを開閉することを確認します。

  4. 他のabout.astroblog.astroの2ページにも同じ<script>とインポートを追加し、両ページにレスポンシブでインタラクティブなヘッダーがあることを確認します。

      <Footer />
      <script>
        import "../scripts/menu.js";
      </script>
    </body>

:::note[要点]これまでにも、サイトの一部を作成するためにJavaScriptを使用してきました。

  • ページタイトルと見出しの動的な定義
  • 概要ページでのスキルリストのマッピング
  • HTML要素の条件に応じた表示

これらの命令はすべてビルド時に実行され、サイトの静的HTMLを作成したあと、コードは「捨てられます」。

<script>タグ内のJavaScriptはブラウザに送信され、ユーザーの操作に応じてページの更新や入力の切り替えなどを実行します。:::

確認テスト

  1. Astroは、コンポーネントのフロントマターに書かれたJavaScriptをいつ実行しますか?

  2. Astroでは任意でJavaScriptをブラウザに送信できますが、その目的は何ですか?

  3. クライアントサイドのJavaScriptがユーザーのブラウザに送信されるのは、それがどこに書かれた・インポートされたときですか?

チェックリスト

参考

Astroにおけるクライアントサイドスクリプト (EN)

貢献する コミュニティ スポンサー