AstroとWordpressでJamstack その5 Layoutを作る Headerのメニュー(PC)
公開日時:2024-03-25T07:26:20.796Z
HeaderのMenuはやはり重要。まぁスマホでもMenuは使うので、それを前提に再利用可能な形で作っていきます。
今回作成・編集するのは
Heder.astro (編集)
HeaderMenuLink.astro (新規)
HeaderMenuLinkA.astro (新規)
src/js/pcTopMenu.js (新規)
名前にセンスがないのは許して下さい。
HeaderMenuLink.astroが今回一番重要で、役割は
・リンクの配列を作成
・その出力
を行います。
出力の際にHeaderMenuLinkA.astro コンポーネントを使います。
HeaderMenuLinkA.astroはaタグを出力する際にURLを判断し、開いているページのURLならクラスを付けます。(公式から流用)
Menuに関してWPのRestApiから取る方法もあるのですが、ディレクトリ構造のこととか考えると新たに定義するほうが無難と判断しました。
それではHeaderMenuLinkA.astroから。
HeaderMenuLinkA.astro
---
import type { HTMLAttributes } from 'astro/types';
type Props = HTMLAttributes<'a'>;
const { href, class: className, ...props } = Astro.props;
const { pathname } = Astro.url;
const isActive = href === pathname || href === pathname.replace(/\/$/, '');
---
<a class="inline-block p-3 md:p-1" href={href} class:list={[className, { active: isActive }]} {...props}>
<slot />
</a>
<style>
a {
display: inline-block;
text-decoration: none;
}
a.active {
font-weight: bolder;
text-decoration: underline;
}
</style>
流用なのでよくわかってないですが、役割は先程述べた通り。
HeaderMenuLink.astro
---
import HeaderMenuLinkA from "./HeaderMenuLinkA.astro";
export interface headerMenuLinkChild{
id:number;
name:string;
url:string;
}
export interface headerMenuLink {
id:number;
name:string;
url?:string;
childLink?:headerMenuLinkChild[];
}
const linkList :headerMenuLink[] =[
{id:1 ,name:'Home',url:'/'},
{id:2 ,name:'About',url:'/about/'},
{id:3 ,name:'Contact',url:'/contact/'},
{id:4 ,name:'Blog',url:'#!',childLink:[
{id:5 ,name:'Archive All',url:'/blog'},
{id:7 ,name:'Technology',url:'/blog/tecnology'},
{id:8 ,name:'Etc',url:'/blog/etc'},
]},
]
---
<ul class="lg:flex">
{linkList.map((link) => (
// ...link を使って各要素を展開
<li class="lg:flex md:w-fit w-full p-2 md:p-3 relative" >
<HeaderMenuLinkA href={link.url} >
{link.name} {link.childLink &&
<svg class="hidden lg:inline-block w-2.5 h-2.5 ms-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"></path>
</svg>
}
</HeaderMenuLinkA>
{link.childLink && (
<div class="sub-menu lg:hidden md:absolute md:top-10 md:bg-slate-100 p-5 md:shadow md:-left-4 md:w-36">
<ul class="">
{link.childLink.map((childLink) => (
<li >
<HeaderMenuLinkA href={childLink.url} >
{childLink.name}
</HeaderMenuLinkA>
</li>
))}
</ul>
</div>
)}
</li>
))
}
</ul>
まず export interfaceでリンクの配列を定義します。
headerMenuLinkChildでサブメニュー用の定義
headerMenuLink で親配列を定義します。
IDを振ってますが別に使っていないのは秘密。
linkListでinterfaceを使って実際の配列を定義しています。
id:4 Blog のところで、childLinkを使いサブメニューを定義しています。
装飾はTailwindcssですので、ご自由に。
37行目
{link.childLink && (
ほげほげ
)}
この形はほかでもよく使います。childLinkに値があれば実行する、なければ何もしないという書き方です。
pcTopMenu.js
//すべてのサブメニューを取得(上下にあったりする)
const subMenus = document.querySelectorAll('.sub-menu');
//console.log(subMenus);
//取得したサブメニューの親要素a にイベントリスナーを設定
subMenus.forEach(function(subMenu){
const parentSubMenu = subMenu.parentNode;
const aSubMenu = parentSubMenu.firstElementChild;
aSubMenu.addEventListener('click',function(e){
e.preventDefault();
})
parentSubMenu.addEventListener('click',function(e){
subMenu.classList.toggle('openSubmenu');
if(subMenu.classList.contains('openSubmenu')){
subMenu.classList.add();
subMenu.classList.remove('lg:hidden');
}else{
subMenu.classList.remove();
subMenu.classList.add('lg:hidden');
}
})
})
Header.astro
---
import HeaderMenuLink from "../compornents/HeaderMenuLink.astro"
---
<header>
<div>
ここにヘッダー関連
</div>
<nav>
<HeaderMenuLink />
</nav>
</header>
装飾は後回し。
以上で
このような表示になるはず。
サブメニューに関しては、TailwindでGroupしてhoverでtabindexする方法もありますが、今回はJSで作りました。
AstroPress