18
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Gatsby.jsAdvent Calendar 2019

Day 21

Gatsby組込みのLinkコンポーネントを使ってナビゲーションバーを自作する

Last updated at Posted at 2019-12-21

初めに

この記事はGatsby.js Advent Calendar 2019 21日目の記事です。
GatsbyJSを色々いじってたらいい感じのナビゲーションバーが自作できた気がしました。

目次

  • 本記事の目標
  • 前提 - 開発環境 -
  • Gatsby Link APIについて
  • ディレクトリ構成
  • まずはひな型を作る
  • 共通のレイアウトはLayoutコンポーネントとして定義する
  • Headerコンポーネントの実装
  • 終わりに

本記事の目標

こんな感じのナビゲーションバーを作りたいと思います。
それっぽいものがフロントエンド初心者の私でも作れたので投下します。
重要なことですが、このレイアウトではBootstrap4は使っていません。

サンプルを公開しています。触ってみてください → サンプル
ソースコード→ https://github.com/koralle/gatsby-link-navbar

無題.png

前提 - 開発環境 -

以下私の手元の開発環境になります。

  • Windows 10
  • yarn 1.21.1
  • Gatsby CLI version: 2.8.15

Gatsby Link APIについて

このナビゲーションバーを作るうえで、今回はGatsby組込みのGatsby Link APIを使用しています。
簡単に説明すると、サイト内リンクをこのGatsby Link APIを使って実装すると、そのリンクを踏んで画面遷移する前に、関連するリソースを事前にfetchしてくれる(公式ではこれを"preloading"と呼んでいる)ので、結果的にサイトパフォーマンスの向上につながります。

今回はこのGatsby Link APIの中の**Link**コンポーネントを使用します。

公式ドキュメント→Gatsby Link API | GatsbyJS

これに関しては12/25の投稿日に記事を書けたらいいなと思います。

ディレクトリ構成

gatsby-link-navbarというプロジェクトを作成し、/src以下のディレクトリを編集しました。
gatsby-link-navbar/src/components/以下のファイルが画面のレイアウトを作ります。

> tree src
HOGEHOGE\GATSBY-LINK-NAVBAR\SRC
├─components
│  ├─Header
│  │      Header.css
│  │      Header.js
│  │
│  └─Layout
│          Layout.css
│          Layout.js
│
└─pages
        about.js
        hobby.js
        index.js
        link.js
        skills.js

このような構成にすることで、リソース、URL、そしてコンテンツが以下のような対応関係になるようにしました。
ただ、今回は意図したレイアウトが描画されていることが確認できればOKなので、gatsby-link-navbar/src/pages/以下は今回ほとんど作りこんでません。

リソース | URL |コンテンツ
----------------------+-------------------------+-----------
./src/pages/about.js | localhost:8000/about/ | "About"
./src/pages/hobby.js | localhost:8000/hobby/ | "Hobby"
./src/pages/index.js | localhost:8000 | トップ画面
./src/pages/link.js | localhost:8000/link/ | "Link"
./src/pages/skills.js | localhost:8000/skills/| "Skills"

まずはひな型を作る

今回はstarterとしてgatsby-starter-hello-worldを使います。

> gatsby new gatsby-link-navbar https://github.com/gatsbyjs/gatsby-starter-hello-world

次のコマンドを叩いた後、ブラウザでlocalhost:8000にアクセスして"Hello, world!"が表示されていることを確認してください。

> cd gatsby-link-navbar
> gatsby develop

共通のレイアウトはLayoutコンポーネントとして定義する

まずは全ページ共通のレイアウトをLayoutコンポーネント(layout.js)として作成します。
先にlayout.jsの内部を確認します。

layout.js
import React from 'react';
import Header from '../Header/Header';
import './Layout.css';

export default ({ children }) => (
    <div className="page-root">
        <Header />
        <div className="page-body">
            {children}
        </div>
    </div>
)

大雑把に言えばHeaderコンポーネントとページの中身を収容する<div>タグを縦に並べています。
Layoutコンポーネントをこのように定義すると、個々のコンテンツを描画するコードは以下のように書くことができます。

./src/pages/hogehoge.js

{/* "hogehoge"ページ */}
const Hogehoge = () => {
    return (
        <Layout>
      {/* ここにlayout.js内の{children}に当たる内容を記述する。 */}
        </Layout>
    );
}

Layout.jsHeader.jsに依存しているので、次にHeaderコンポーネントつまりナビゲーションバーを実装します。

Headerコンポーネントの実装

Linkコンポーネントを使用するために、まずはLink APIをインポートします。

// Gatsby標準組込みなので事前の"yarn add"や"npm install"の必要はなし。
import { Link } from 'gatsby';

私はナビゲーションバーに表示したい項目を例えば以下のようにしました。

// ナビゲーションバーに表示する項目
const NavMenuItem = ["Home", "About", "Skills", "Hobby", "Link"];

次に、ナビゲーションバーの項目のそれぞれに設定するスタイルを記述します。

今回はアクティブになっている項目のLinkコンポーネントは色を反転させ、太字にします。
私はHeader.js内ではアクティブ時と非アクティブ時の差分のみを記述し、それ以外でLinkコンポーネントに適用したいスタイルは同じ階層のHeader.cssに記述しました(この辺は好みの問題だと思います)。


// 普段のリンクはこのスタイル
const LinkStyles = {
    background: 'rebeccapurple',
    color: 'white',
    fontWeight: "normal"
}

// アクティブになった項目は色を反転させる
const ActiveStyles = {
    background: 'white',
    color: 'rebeccapurple',
    fontWeight: "bold",
}

この二つのスタイルをナビゲーションバーに表示する項目(=Linkコンポーネント)全てに適用します。
アクティブ時と非アクティブ時の切り替えはGatsby側が引き受けてくれるので、スタイルの切り替え処理を私たちが記述する必要がありません。

const NavMenuLiTag = NavMenuItem.map((item) => {
    let page_link = "";
    if (item === "Home") {
        page_link = "/";
    }
    // e.g.) "/about/", "/hobby/"
    else page_link = "/" + item.toLowerCase() + "/"; 

    return (
        <li key={page_link}>
            <Link to={page_link} style={LinkStyles}
                activeStyle={ActiveStyles}
                className="page-link"
            >
                {item}
            </Link>
        </li>
    )
});

最終的にHeaderコンポーネントは以下のようになりました。

./src/components/Header/Header.js
import React from 'react';
import { Link } from 'gatsby';
import './Header.css'

const Header = (props) => {
    // ナビゲーションバーに表示するリンク
    const NavMenuItem = ["Home", "About", "Skills", "Hobby", "Link"];

    // 普段のリンクはこのスタイル
    const LinkStyles = {
        background: 'rebeccapurple',
        color: 'white',
        fontWeight: "normal"
    }

    // アクティブになったリンクは色を反転させる
    const ActiveStyles = {
        background: 'white',
        color: 'rebeccapurple',
        fontWeight: "bold",
    }

    // ナビゲーションリンクの作成
    const NavMenuLiTag = NavMenuItem.map((item) => {
        let page_link = "";
        if (item === "Home") {
            page_link = "/";
        }
        else page_link = "/" + item.toLowerCase() + "/";

        return (
            <li key={page_link}>
                <Link to={page_link} style={LinkStyles}
                    activeStyle={ActiveStyles}
                    className="page-link"
                >
                    {item}
                </Link>
            </li>
        )
    });

    return (
        <header className="App-header">
            <nav className="App-navbar">
                <p className="App-logo"><Link to="/" >koralle</Link></p>
                <div className="App-navbar-item">
                    <ul>
                        {NavMenuLiTag}
                    </ul>
                </div>
            </nav>
        </header>
    );
}

export default Header;

終わりに

訂正等あればコメントお願いします...

18
9
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?