インタラクティブでシームレスなフォームテンプレート「Abu al-Haul」

またの名を「スフィンクスはどら焼の栗を食べるか?」

それはさておき、構想から一ヶ月超。漸く形になりました。

お問い合わせフォームに関して、「こんな機能があったら良いなー」と自分が考えたものを詰め込んだテンプレートを作成しました。

完成図

Abu al-Haul フォーム画面
Abu al-Haul フォーム画面

フォームのデザイン自体はBootstrap4ほぼそのままです。

リポジトリ

名前の由来

機能の前に軽く名前の由来を。明らかにアラビアっぽい雰囲気の名前ですが、意味はスフィンクス。ええ、あのスフィンクスです。直接の意味は「恐怖の父」で、スフィンクスの別名だそうです。

ではなぜスフィンクスかというと、お問い合わせフォームのテンプレートということで「質問」や「問いかけ」にまつわるものの名前を付けようと考えたためです。

妖怪だと「蟹坊主」辺りかな、と思ったのですが「Kani-bouzu」はあまりしっくり来ませんでした。禅問答ということで「狗子仏性」は長いですし、「禅」だけだと色々他の名前とダブりそうだったのでパス。

ということで西洋に目を向けて、ギリシャでオイディプスに謎掛けをしたスフィンクス(そういう意味ではクフ王のピラミッドの前にいるスフィンクスとは厳密には別物だと思いますが)にちなむことにしました。

朝は足が4本、昼は2本、夜は3本。この生き物は何か?

という謎掛けですね。そこそこ有名ではないかと思います。

なお、選択肢は「ヒト」「人間」「ホモ・サピエンス」からの三択でお願いします(セラフィック・ローサイトが飛んできそう)。

機能

今回取り入れた機能は下記の通り。

  • イマドキっぽさ
    • インタラクティブ性
      • Vue.jsのデータバインディングを利用して、入力に即応してバリデーションを行います
      • 送信ボタンの有効/無効化
        • 項目全てでバリデーションOKになるまで送信ボタンはdisabled(押下できない無効状態)となります
    • シームレス
      • Vue.jsのトランジションとVue Routerを使用することで、画面遷移の瞬間を意識させずにシームレスに表示を切り替えるようにしました
    • プログレスバー
      • 送信処理実行中は画面上端に細いプログレスバーを表示させる今っぽいデザインのプログレスバーを採用
  • メンテナンス性・カスタマイズ性
    • フォーム本体と設定項目を分離することで、プログラムの修正なしで入力項目の増減や必須・最大文字数等の条件を変更できるようにしました
    • フォーム本体も名称や著者情報等を個別の設定ファイルに分離し、なるべくソースコードに手を入れなくても良いようにしました
    • オプション: いくつかの設定項目はオン/オフが可能です
      • confirm: 確認画面を表示させるか否か。trueにするとフォームの下に「確認」ボタンが表示され、押下すると確認画面がモーダルで表示されます。falseの場合は「確認」ではなく「送信」ボタンになり、押下で即送信処理を実行します。
      • recaptchamode: reCAPTCHA(v2)を使用するか否か。trueの場合、フォームの項目と「確認」or「送信」ボタンの間にreCAPTCHAを出力します。reCAPTCHAの設定はrecaptcha.phpに記述をしてください
      • devmode: 開発モードか否か。trueの場合、Mailtrap.ioを使用してメールの送信テストが可能になります。mailtrapの設定はmailtrap.phpに記述をしてください。なお、falseの場合はmailconfig.phpに記述された設定を使用して、通常のメール送信を試みます。
    • エラーメッセージ(バリデーションエラー時メッセージ)も設定ファイルで変更可能です
    • Vueコンポーネントを使用し、入力項目そのもの(inputタグ等)と、それを囲むボックス・ラベル等を分離することで、デザインのカスタマイズの際に後者のみを編集することでデザインの変更がある程度効くように心掛けました
  • 郵便番号の補完
    • nasum/yubinbango-coreを使用することで、郵便番号入力時に住所を自動で補完します
      • type="postalcode"を指定したテキストボックスから、(key)にaddressを指定したテキストボックスへ補完します
  • セキュリティ
    • CSRFトークン: 一応フォーム表示時にCSRF対策用のトークンを発行し、フォーム内容送信時にトークンをチェックしています
    • reCAPTCHA: reCAPTCHA v2に対応し、スパム等の機械的なメール送信をある程度抑制できます(vue-recaptcha使用)
  • その他
    • 入力ボックスからフォーカスが外れると、半角文字を全角文字へ自動的に変換(環境によっては半角カタカナはメールが化けるので)

機能盛り盛りです。

技術的な話

自身の学習のために

  • イマドキのJavaScriptフレームワーク
  • 何かしらのPHPフレームワーク

を組み合わせたものを作りたかった、というのも根底にありました。

ただし、Laravelはフレームワークとしては大き過ぎたのと、Laravel Mixを使えばVue.jsが使用可能になるためセットでの使用が簡単にできます。そうではなく、「個別のJSフレームワークとPHPフレームワークを組み合わせる」にはどうしたら良いのか(特にディレクトリ構造)が自分の中でピンと来ていなかったので、あえてLaravelを候補から外して挑んでみました。

結果として、上記のインタラクティブ・シームレスの部分でVue.jsを使用し、バックエンドのPHPフレームワークは極力薄く小さいものということでDietCakeを採用しました。

色々と手探りでやったので書き方として合っているのかどうかは分かりませんが、形にはできたので自分としては成長できたのではないかと思います。

作っている途中で躓いた部分は都度アウトプットしたので、そういう意味でも引き出しが増えたのではないかと思います。

スクリーンショットとサンプル

例えば、config.ymlでいくつかのパラメータを変更してみます。

appname: 'すふぃんくす!'
authorname: 'オイディプス'
create_year: 2018
recaptchamode: false

すると、下図のようにフォームが変化します。冒頭のフォームと比較すると、ヘッダの名称が変わったり、フッタの著者情報が代わったり、reCAPTCHAが消えたりしています。

設定ファイルを編集すると項目が変化する
設定ファイルを編集すると項目が変化する

次に、form.ymlの先頭にcompanyという項目を追加してみます。

company:
    label: 会社名
    type: text
    required: false
    placeholder: "株式会社〇〇"
    maxlength: 50
name:
    label: お名前
    type: text
    required: true
    placeholder: "お名前 太郎"
    maxlength: 30
furigana:
## 以下略

すると、下図のように変化します。確かに「会社名」が追加されています。

「会社名」の項目を追加
「会社名」の項目を追加

config.ymlのオプション、confirmfalseにしてみます。

confirm: false

すると、下図のように「確認」ボタンが「送信」ボタンに変化しました。実際の挙動も、確認のモーダルが開かずに即座に送信処理を実行するようになります。

確認ボタンが送信ボタンに早変わり
確認ボタンが送信ボタンに早変わり

送信画面

送信処理中の画面は下図のようなイメージです。冒頭の「プログレスバー」でも記しましたが、上端に沿う細いバーのデザインにしました。画面内はローディングアニメーションと同じものです。

プログレスバーは画面上端に沿う形に
プログレスバーは画面上端に沿う形に

送信完了画面。シンプルですがこんなイメージ。

送信完了画面
送信完了画面


話をし出すとキリがなくなってしまうのでこの辺で。細かい調整やバグがあるかもしれませんが、ひとまず形になったということで。

余談1

ちなみに、伝説ではオイディプス王に正解を言われてしまったスフィンクスは崖から飛び降りて自滅したそうです。

それでは、ここでpackage.jsonを見てみましょう。特にnpm scriptsの部分。

    "scripts": {
        "what:is": "mkdirp src/assets/scss src/assets/scss/assets src/assets/scss/assets/bootstrap src/assets/scss/assets/bootstrap/honoka src/assets/scss/assets/bootstrap/honoka/bootstrap src/assets/scss/assets/bootstrap/honoka/honoka src/assets/scss/assets/bootstrap/honoka/bootstrap/scss src/assets/scss/assets/bootstrap/honoka/bootstrap/scss/mixins src/assets/scss/assets/bootstrap/honoka/bootstrap/scss/utilities public/app/config/usersettings",
        "that": "npm-run-all -p which:has one:voice and:yet becomes fourfooted:and twofooted:and threefooted",
        "which:has": "copyfiles -f \"./node_modules/bootstrap-honoka/scss/*.scss\" \"./src/assets/scss/assets/bootstrap\"",
        "one:voice": "copyfiles -f \"./node_modules/bootstrap-honoka/scss/honoka/_honoka.scss\" \"./src/assets/scss/assets/bootstrap/honoka\"",
        "and:yet": "copyfiles -f \"./node_modules/bootstrap-honoka/scss/honoka/*.scss\" \"./src/assets/scss/assets/bootstrap/honoka/honoka\"",
        "becomes": "copyfiles -f \"./node_modules/bootstrap/scss/*.scss\" \"./src/assets/scss/assets/bootstrap/honoka/bootstrap/scss\"",
        "fourfooted:and": "copyfiles -f \"./node_modules/bootstrap/scss/mixins/*.scss\" \"./src/assets/scss/assets/bootstrap/honoka/bootstrap/scss/mixins\"",
        "twofooted:and": "copyfiles -f \"./node_modules/bootstrap/scss/utilities/*.scss\" \"./src/assets/scss/assets/bootstrap/honoka/bootstrap/scss/utilities\"",
        "threefooted": "node ./bin/wehemmesut",
        "serve": "node bin/facelessblack && vue-cli-service serve",
        "build": "node bin/facelessblack && node bin/awlad && vue-cli-service build",
        "start": "npm-run-all -s what:is that",
        "human": "rimraf ./src/assets/scss ./public/app/config/core.php ./public/app/config/usersettings ./composer.lock ./package-lock.json"
    },

初期設定としてnpm startを実行すると、what:is thatの2つのサブルーチンが実行されます。特にthatの方はさらにnpm-run-all -p which:has one:voice and:yet becomes fourfooted:and twofooted:and threefootedとなっています。

全部を繋げるとwhat:is that which:has one:voice and:yet becomes fourfooted:and twofooted:and threefooted。はい、冒頭の「朝は足が4本、昼は2本、夜は3本。この生き物は何か?」を英語にしたものになります。

ついでにnpm run humanとするとどうなるか。rimrafによって、先ほどの初期設定で配置されたファイルを削除してgit cloneした直後の初期状態(node_modules/ディレクトリは除く)に戻ります。つまり、自滅コマンドというわけです。

ということで、コマンドが伝説になぞらえたものになっているのでした。

余談2

初期設定やnpm run servenpm run buildの際に実行されるnodeのサブルーチンのファイル名について。

wehemmesutawladなんてものがありますね。後はfacelessblack。前者二つに関してはお察しを。最後の1つは名状しがたき何かです。


コーディング中の作業用BGMは下記2曲がメインでした。アラビアンというかラテンっぽいというかそんな音の構成をしていたので、雰囲気作りのために。

  • Ra (Rhythm of Time / Jordan Rudess)
  • So It Ain’t! (Performance & Technique / Bobby Jarzombek)

この記事を書いた人

アバター

アルム=バンド

フルスタックエンジニアっぽい何か。LAMPやNodeからWP、gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。