初めに
この記事はGatsby.js Advent Calendar 2019 21日目の記事です。
GatsbyJSを色々いじってたらいい感じのナビゲーションバーが自作できた気がしました。
目次
- 本記事の目標
- 前提 - 開発環境 -
- Gatsby Link APIについて
- ディレクトリ構成
- まずはひな型を作る
- 共通のレイアウトは
Layout
コンポーネントとして定義する -
Header
コンポーネントの実装 - 終わりに
本記事の目標
こんな感じのナビゲーションバーを作りたいと思います。
それっぽいものがフロントエンド初心者の私でも作れたので投下します。
重要なことですが、このレイアウトではBootstrap4は使っていません。
サンプルを公開しています。触ってみてください → サンプル
ソースコード→ https://github.com/koralle/gatsby-link-navbar
前提 - 開発環境 -
以下私の手元の開発環境になります。
- 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
の内部を確認します。
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
コンポーネントをこのように定義すると、個々のコンテンツを描画するコードは以下のように書くことができます。
{/* "hogehoge"ページ */}
const Hogehoge = () => {
return (
<Layout>
{/* ここにlayout.js内の{children}に当たる内容を記述する。 */}
</Layout>
);
}
Layout.js
はHeader.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
コンポーネントは以下のようになりました。
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;
終わりに
訂正等あればコメントお願いします...