こんにちは、ryohei(@ityryohei)です!

本記事は、Vue.jsというJavaScriptのフレームワークを使って、ドロップダウンメニューを作成する方法をご紹介しています。

私は最近、PHPのフレームワークであるLaravelや純粋なJavaScriptの勉強に時間を取っていまして、Vue.jsを触るのはかなり久しぶりになります。というのも、Vue.jsが実務で採用されることはしばらくなさそうなので、他言語のフレームワークやJavaScriptの勉強に力を入れていました。

ただ、多言語の勉強をしていても、Vue.jsの存在は個人的にかなり気になっていまして。どうせなら一緒に勉強しよう! ということで、今後はVue.jsも一緒に勉強していきたいと思います。

復帰第一弾として、今回は実務でドロップダウンメニューを作る機会がありましたのでVue.jsで組んでみました。いつもであれば慣れているJavaScriptやjQueryで実装するのですが、違ったものを取り入れることによって新鮮な気持ちでコーディングすることができ、リフレッシュになって良いですね!

もっと良い実装方法があるかと思いますので、参考程度に見ていただければと思います。

では、解説していきます。

マウスオーバーで開閉するドロップダウンメニュー

マウスオーバーで開いて、マウスリーブで閉じるドロップダウンメニューを作成していきたいと思います。下記のデモのような動きとなります。「Service」と記載された部分にマウスカーソルを載せるとドロップダウンメニューが開きます。

See the Pen
Dropdown Menu | Vue.js
by ryohei (@intotheprogram)
on CodePen.

スクリプト→HTMLの順番でご紹介していきたいと思います。

JS

JS側でナビゲーションとドロップダウンメニューに表示するアイテムを「items」に指定しています。「isOpen」が「true」になるとドロップダウンメニューが表示されます。ドロップダウンメニューの内容は「children」の部分となります。

mthodsにはマウスオーバーとマウスリーブによって「isOpen」の真偽を切り替えています。

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var nav = new Vue({
    el: '#nav',
    data: {
        isOpen: false,
        items: [
            {
                url: '#',
                name: 'Home'
            },
            {
                url: '#',
                name: 'About'
            },
            {
                url: '#',
                name: 'Service',
                children: [
                    {
                        url: '#',
                        name: 'Service1'
                    },
                    {
                        url: '#',
                        name: 'Service2'
                    },
                    {
                        url: '#',
                        name: 'Service3'
                    },
                ]
            },
            {
                url: '#',
                name: 'Contact'
            }
        ]
    },

    methods: {
        mouseover: function () {
            this.isOpen = true;
        },
        mouseleave: function () {
            this.isOpen = false;
        }
    }
});
</script>

以上でJSの記述は完了です。

HTML

続いてHTMlを作成していきます。「items」の部分はループをネストして表示しています。今回作成するドロップダウンメニューは、ドロップダウンの親はリンクである必要はなかったので、ifで条件分岐をしてaタグとspan表示を切り替えるようにしています。spanタグがマウスオーバー・マウスリーブされることによって、ドロップダウンメニューの「isOpen」が切り替わるようにしています。

<header>
    <nav id="nav">
        <h1>Site Title</h1>
        <ul>
            <li
                v-for="item in items">
                <a :href="item.url"
                   v-if="!item.children">
                    {{ item.name }}
                </a>
                <span
                    v-else
                    v-on:mouseover="mouseover"
                    v-on:mouseleave="mouseleave">
                    {{ item.name }}

                    <ul class=" dropdown"
                       :class="{ isOpen }">
                        <li
                            v-for="child in item.children">
                            <a :href="child.url">
                                {{ child.name }}
                            </a>
                        </li>
                    </ul>
                </span>
            </li>
        </ul>
    </nav>
</header>

CSS

最後にスタイルを定義して完了です。命名を考える前に表示確認のために子セレクタを使用しています。実際に使用される際にはidやclassで命名していただければと思います。

header {
    width: 100%;
    background-color: #007db9;
}

#nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    max-width: 1280px;
    margin: 0 auto;
}

#nav h1 {
    margin: 0 0 0 20px;
    color: #fff;
}

#nav > ul {
    display: flex;
    margin: 0;
    padding: 0;
    list-style-type: none;
}

#nav > ul > li {
    margin: 0 20px 0 0;
}

#nav > ul > li > a {
    display: block;
    height: auto;
    padding: 20px;
    color: #fff;
    text-decoration: none;
}

#nav > ul > li > span {
    position: relative;
    display: block;
    height: auto;
    padding: 20px;
    color: #fff;
    text-decoration: none;
}

#nav > ul > li > span:after {
    content: '▼';
    display: inline-block;
    transform: rotate(90deg);

}

.dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    display: none;
    padding: 0;
    list-style-type: none;
    background-color: #007db9;
}

.dropdown li {
    width: 250px;
    border-bottom: 1px solid #fff;
}

.dropdown li a {
    display: block;
    padding: 10px;
    color: #fff;
    text-decoration: none;
}

.isOpen {
    display: block;
}

以上でマウスオーバーで開閉するドロップダウンメニューは作成完了です。

クリックで開閉するドロップダウンメニュー

続いてマウスクリックやタップで開閉するドロップダウンメニューのご紹介です。下記はデモになります。

See the Pen
Dropdown Menu2 | Vue.js
by ryohei (@intotheprogram)
on CodePen.

全体的に大きな変更はありません。CSSは上でご紹介したものと同様のものになります。JSのmethodsとHTML側のv-on部分を少し修正するだけです。それだけでマウスオーバーからクリックで開閉するドロップダウンメニューに変更することができます。(素敵!)

では、早速ソースを見ていきましょう。

JS

var nav = new Vue({
    el: '#nav',
    data: {
        isOpen: false,
        items: [
            {
                url: '#home',
                name: 'Home'
            },
            {
                url: '#about',
                name: 'About'
            },
            {
                url: '#service',
                name: 'Service',
                children: [
                    {
                        url: '#service1',
                        name: 'Service1'
                    },
                    {
                        url: '#service2',
                        name: 'Service2'
                    },
                    {
                        url: '#service3',
                        name: 'Service3'
                    },
                ]
            },
            {
                url: '#contact',
                name: 'Contact'
            }
        ]
    },
    methods: { 
        open: function () {
            this.isOpen = !this.isOpen;
        }
    }
});

methodsopenはisOpen変数の値をトグルしています。isOpenがtrueであればfalseを代入といった処理になります。

続いてHTML側を見てみます。

HTML

<!doctype html>
<html lang="ja">

<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="">
    <meta name=" robots" content="noindex">
    <meta name="description" content="">
</head>

<body>
    <header>
        <nav id="nav">
            <ul>
                <li
                    v-for="item in items">
                    <a :href="item.url"
                       v-if="!item.children">
                        {{ item.name }}
                    </a>
                    <span
                        v-else
                        v-on:click="open">
                        {{ item.name }}
                        
                        <ul class=" dropdown"
                           :class="{ isOpen }">
                            <li
                                v-for="child in item.children">
                                <a :href="child.url">
                                    {{ child.name }}
                                </a>
                            </li>
                        </ul>
                    </span>
                </li>
            </ul>
        </nav>
    </header>
</body>
</html>

こちらも大きな変更はありませんね。span指定したv-onを修正して、メソッドの実行結果によって「isOpen」の値が変わることでドロップダウンメニューが開閉するようになっています。

以上でクリックで開閉するドロップダウンメニューの作成は完了となります。

最後に

本記事で解説した内容のデモを再度ご紹介して終わりにしたいと思います。

マウスオーバーで開閉するドロップダウンメニュー

See the Pen
Dropdown Menu | Vue.js
by ryohei (@intotheprogram)
on CodePen.

クリックで開閉するドロップダウンメニュー

See the Pen
Dropdown Menu2 | Vue.js
by ryohei (@intotheprogram)
on CodePen.

Vue.jsは触り始めたばかりでわからないことが多いですが、もっと見晴らしの良いコーディングができるようにこれからも勉強を続けていきたいと思います!

以上、Vue.jsでドロップダウンメニューを作成する方法のご紹介でした!