スポンサーリンク

Elm0.19でCSSフレームワーク”Bulma”を試してみる(4)ハンバーガーメニュー

2019年6月11日

以前、Vue.jsを触っていた時に、以下の記事がわかりやすくて感動しました。

https://qiita.com/isamusuzuki/items/5ec800e423a3a56ef03d

Vue.jsには、状態管理の方法としてvuexというものがあります。

引用元: https://vuex.vuejs.org/ja/

この絵は、ElmのMODEL,UPDATE,VIEWと全く同じです。

なので、真似してみたいと思います。

スポンサードリンク

今回やりたいこと

  • ElmのSPA(SinglePageApplication)にBulmaを組み込む
  • Bulmaのレスポンシブなハンバーガーメニューを実装する

ソースコード
https://github.com/adash333/elm-bulma-hamburger

DEMOサイト
https://laughing-jepsen-024a72.netlify.com/

開発環境

Windows 10 Pro
Chrome
VisualStudioCode 1.32.3
git version 2.20.1.windows.1
nvm 1.1.7
node 10.2.0
npm 6.4.1
elm 0.19.0-bugfix6
elm-format 0.8.1
VisualStudioCodeの拡張機能でelmをインストールして、settings.jsonに以下のようにelmを設定。
(『Alt + Shift + F』と『Ctrl + S』を使用。)

    "[elm]": {
        "editor.formatOnSave": true
    },

新規Elmアプリの作成

C:/elm/ フォルダに、elm-bulma-hamburger/ フォルダを作成し、VisualStudioCodeで開き、Ctrl+@でコマンドプロンプトを開き、以下を入力します。
途中で何か聞かれたらEnterを押します。

elm/url パッケージもインストールしておきます。

elm init
elm install elm/url

ElmでBulmaを使用し、Netlifyにデプロイするための準備

Browser.applicationからbulmaを使用し、Netlifyにデプロイするための以下の3つのファイル(index.html, .gitignore, netlify.toml)をコピペします。

src/Main.elmの新規作成

以下のソースコードをほぼコピペします。
参考:Elmで複数ページからなる極簡単なSPA(シングルページアプリケーション)を作成(ソースコードあり)

https://github.com/adash333/elm-navigation2/blob/master/src/Main.elm

また、いらすとやから画像を3つダウンロードして、img/フォルダに保存します。

ここで一度、elm-liveで開発サーバで表示してみます。

elm-live src/Main.elm --open -- --output=main.js

ここまでのコードを、GitHubへpushします。
https://github.com/ にログインして、新規リポジトリを作成します。
今回は、リポジトリの名前は elm-bulma-hamburger としました。

Ctrl+C => y + Enterでサーバを停止してから以下を入力して、GitHubへpushします。

git init
git add .
git commit -m "first commit"
git remote add origin https://github.com/adash333/elm-bulma-hamburger.git
git push -u origin master

この時点でのソースコード
https://github.com/adash333/elm-bulma-hamburger/tree/896743d790e42fd22aa53d95de1106cac7bb2d0c

AboutページとContactページの上の部分を編集

elm-live src/Main.elm –open — –output=main.js で見ながら、少し見栄えを変更します。

case model.url.path of
            "/" ->
                div [] []

            "/about" ->
                section [ class "hero is-primary is-bold" ]
                    [ div [ class "hero-body" ]
                        [ div [ class "container" ]
                            [ h1 [ class "title is-size-2" ] [ text "About" ]
                            , h2 [ class "subtitle is-size-4" ] [ text "EBHとは?" ]
                            ]
                        ]
                    ]

            "/contact" ->
                section [ class "hero is-info is-bold" ]
                    [ div [ class "hero-body" ]
                        [ div [ class "container" ]
                            [ h1 [ class "title is-size-2" ] [ text "Contact" ]
                            , h2 [ class "subtitle is-size-4" ] [ text "お問い合わせ" ]
                            ]
                        ]
                    ]

            _ ->
                div [] []

ナビゲーションバーをVIEWに記載する

こちらのコードを参考に、HTML to ELMのを使いつつ、VIEWにナビゲーションバーのコードの一部を記載してみます。

nav [ attribute "aria-label" "main navigation", class "navbar is-white", attribute "role" "navigation" ]
            [ div [ class "navbar-brand" ]
                [ div [ class "navbar-item" ]
                    [ text "EBH" ]
                , div [ class "navbar-burger", attribute "data-target" "navMenu" ]
                    [ span []
                        []
                    , span []
                        []
                    , span []
                        []
                    ]
                ]
            , div [ class "navbar-menu", id "navMenu" ]
                [ div [ class "navbar-end" ]
                    [ a [ class "navbar-item", href "/" ]
                        [ text "トップ" ]
                    , a [ class "navbar-item", href "/about" ]
                        [ text "NBHとは?" ]
                    , a [ class "navbar-item", href "/contact" ]
                        [ text "お問い合わせ" ]
                    ]
                ]
            , text "  "
            ]

一応、レスポンシブになっています。ちょっとだけ、それっぽくなってきました。
HTML to ELM  が必須でした。

attribute “aria-label" “main navigation" 
という書き方は 、TML to ELM を使わなければ、たどり着けませんでした。

ここまでのソースコード
https://github.com/adash333/elm-bulma-hamburger/tree/09f094e692115dd44726700e7a972dc505dabc91

ハンバーガーメニューをトグルさせる

横幅が狭いときに、ナビゲーションバーの右端に出てくる3本線の『ハンバーガーメニュー』をクリックすると、ナビゲーションメニューが縦に広がって表示されるようにします。

参考:ハンバーガーメニューをトグルさせる

Vue.jsでの、
@click="toggleMenu" :class="{'is-active’: isMenuActive}" 
の、@click は onClick でよいと思うのですが、
:class を、elmでどのように記載したらよいでしょうか?

参考: Vue.jsのv-bind:class について

https://jp.vuejs.org/v2/guide/class-and-style.html

elmの場合は、modelに isMenuActive: Bool を定義して、case model.isMenuActive of のTrueとFalseで場合分けして記載する感じでしょうか?それともif then elseでもいけるでしょうか?

参考:https://github.com/ababup1192/elm-spa-example/blob/master/src/Main.elm

試しにMODEL、UPDATE、VIEWを以下のように変更してみます。

(変更前)

-- MODEL

type alias Model =
    { key : Nav.Key
    , url : Url.Url
    }

init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
init flags url key =
    ( Model key url, Cmd.none )

-- UPDATE

type Msg
    = LinkClicked Browser.UrlRequest
    | UrlChanged Url.Url

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        LinkClicked urlRequest ->
            (省略)
        UrlChanged url ->
            (省略)

-- VIEW

div [ class "navbar-burger", attribute "data-target" "navMenu" ]


div [ class "navbar-menu", id "navMenu" ]

(変更後)

import Html.Events exposing (..)

-- MODEL

type alias Model =
    { key : Nav.Key
    , url : Url.Url
    , isMenuActive: Bool
    }

init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
init flags url key =
    ( Model key url (isMenuActive False), Cmd.none )

-- UPDATE

type Msg
    = LinkClicked Browser.UrlRequest
    | UrlChanged Url.Url
    | ToggleMenu

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        LinkClicked urlRequest ->
            (省略)
        UrlChanged url ->
            (省略)
        ToggleMenu ->
            if model.isMenuActive then ( { model | isMenuActive = False } else ( { model | isMenuActive = True }

-- VIEW

div [ class "navbar-burger", attribute "data-target" "navMenu", onClick toggleMenu, if model.isMenuActive then (class "is-active") else (class "") ]


div [ class "navbar-menu", id "navMenu",  if model.isMenuActive then (class "is-active") else (class "") ]

こんな感じでいろいろ試して、修正したりしたのですが、このMODELのinitのところが一番苦労しました。

elm-liveで開発サーバで表示してみます。

elm-live src/Main.elm --open -- --output=main.js

ハンバーガーメニューのON、OFFはできるのですが、ページ遷移した後、メニューが出っぱなしになってしまいます。

ページ遷移したときにトグルが閉じるようにする

ページ遷移したとき、すなわち、リンクがクリックされたときにトグルが閉じるように(isMenuActiveがFalseになるように)します。

まず、VIEWに、リンクをクリックしたときに、ResetMenu関数を呼び出すように記載します。

VIEW(変更前)

VIEW(変更後)

次に、UPDATEに、この ResetMenu関数 を定義します。リンクをクリックしたら、isMenuActiveがFalseになるようにします。

UPDATE(変更前)

UPDATE(変更後)

elm-liveで開発サーバで表示してみます。

elm-live src/Main.elm --open -- --output=main.js

ブラウザの横幅が狭いとき、ハンバーガーメニューをクリックしてメニュー一覧を出し、リンクをクリックすると、ページ遷移とともに、メニュー一覧も閉じます。

ブラウザの横幅が広いときも特に問題なく動きました。

Netlifyにデプロイ

ターミナル画面で以下を入力して、production用のmain.jsを作成します。(今回はUglify.jsは無視します。)

elm make src/Main.elm --output=main.js --optimize
git add .
git commit -m "ToggleMenu ResetMenu"
git push

ソースコード
https://github.com/adash333/elm-bulma-hamburger

https://www.netlify.com/ にログインして、上記GitHubのリポジトリを選択して、デプロイします。設定欄は空白のままです。

無事、デプロイできたようです。
https://laughing-jepsen-024a72.netlify.com/

ソースコードとDEMOサイト

ソースコード
https://github.com/adash333/elm-bulma-hamburger

DEMOサイト
https://laughing-jepsen-024a72.netlify.com/

スポンサーリンク