#きっかけ
どこかのサイト:「Netlify Formsを使うと、フォーム機能を手軽に作成できます。」
自分:「なるほど。やってみよう。」
(Nuxt+Vuetifyで作ったSPAにお問い合わせフォームをつけようとする)
自分:「わからん。ズバリなサンプルコードも見つからん。」
自分:「自力で開拓するしかないな...」
#環境
vue@2.6.11
nuxt@2.11.0
vuetify@2.1.4
#プレーンなHTMLの場合
プレーンなHTMLから Netlify Forms にPOSTする仕組みの作り方は、form
タグにnetlify
属性をつけるだけ。
例えば以下のようなHTMLを書いてNetlifyにアップ1すると、これを自動的に解析してPOSTできるようにしてくれます。
<!-- 抜粋 -->
<form name="contact" method="POST" netlify>
<input type="text" name="name" />
<input type="text" name="email" />
<input type="text" name="company" />
<textarea name="message"></textarea>
<button type="submit">送信</button>
</form>
たったこれだけ。お手軽ですね!
でも、自分が作りたいのはNuxtベースのSPAなんです。しかもVuetifyを適用。単純には行きません...
#Nuxt+Vuetifyの場合
次のことがわかっていないので、どうにか解決する必要があります。
- どうやってNetlifyにフォームの存在とその内容(項目)を伝えるか
- VuetifyのフォームからPOSTするときにフォームデータをどのように取り扱うか
ひとつずつ見ていきます。
##1. どうやってNetlifyにフォームの存在とその内容(項目)を伝えるか
ダミーのHTMLを使います。このこと自体はNetlifyの公式ブログにも載っています。
ただ、Nuxtでの方法までは書いてありません。どこのフォルダに置くかとか。
Vue単体での事例やReactでの事例などを参考にさせていただきつつ試行錯誤した結果、以下のようにすればOKということがわかりました。
- Nuxt の static フォルダ配下にHTMLを配置
- 名前は任意でよいので、今回は
dummy-contact-form.html
にしました。 - form要素はname属性とnetlify属性が重要。action属性やmethod属性は不要。
- hidden属性をつけておくとhtmlを直接表示してもなにも見えないのでいい感じ。
<!DOCTYPE html>
<html>
<body>
<!-- 完全にダミーフォーム専用 -->
<form name="contact" netlify netlify-honeypot="bot-field" hidden>
<input type="text" name="name" />
<input type="text" name="email" />
<input type="text" name="company" />
<textarea name="message"></textarea>
<input type="text" name="bot-field" />
</form>
</body>
</html>
これをNetlifyにアップすると、Formsが生成されます。
netlify-honeypot について
上記例では、botよけとして`netlify-honeypot="bot-field"`の設定も入れました。 これは、netlify-honeypot属性で指定した項目名のフォーム(ここでは`bot-field`)に何か入力があったら、それはbotの投稿とみなして投稿がブロックされます。 Forms の Spam submissions にすら入りません。##2. Nuxt+VuetifyからPOSTするときにフォームデータをどのように取り扱うか
Nuxt(SPA)からのPOSTなのでaxiosを使ってJavaScriptから非同期で投稿します。
また、Vuetifyを使っているので、input
ではなくv-text-field
、textarea
ではなくv-textarea
を使うことになります。3
具体的には、以下のようにしました。
-
form-name
に、ダミーフォームのform.nameと同じ内容を設定する - 各項目の名前もダミーフォームと一致させる
-
params.append
するときの名前が一致していればOKです。
<template>
<!-- 抜粋です -->
<v-text-field
v-model="name"
label="お名前"
required
/>
<v-text-field
v-model="email"
label="メールアドレス"
required
/>
<v-text-field
v-model="company"
label="会社名(法人の方のみ)"
/>
<v-textarea
v-model="message"
label="お問い合わせ内容"
required
/>
<v-text-field
v-model="botfield"
label="人間は入力しないでください"
v-show="false"
/>
<v-btn color="primary" @click="submit">送信</v-btn>
</template>
<script>
export default {
data() {
return {
name: "",
email: "",
company: "",
message: "",
botfield: "",
}
},
methods: {
async submit() {
const params = new FormData()
//以下、ダミーフォームの各フォーム要素のnameと合わせる
params.append('form-name', 'contact')
params.append('name', this.name)
params.append('email', this.email)
params.append('company', this.company)
params.append('message', this.message)
params.append('bot-field', this.botfield)
const response = await this.$axios.$post(window.location.origin, params)
//実際はresponseを使って画面側にフィードバックさせるが、ここでは仮にconsoleに出力
console.log(response)
},
},
}
</script>
※実際はresponseを使って画面側にフィードバックさせる必要がありますが、ここでは仮にconsoleに出力するだけにしています。また、バリデーションのコードも必要になるでしょう。
##結果
画面はこのようになりました。(適当な値を入力したあとのキャプチャです)
送信したところ、投稿した内容もちゃんとFormsに入りました
#まとめ
Nuxt+Vuetify な SPA から、 Netlify Forms を使うときの対応方法。
- static配下にプレーンなHTMLでダミーフォームを作成し、Netlifyにフォームの存在を認識させる。
- そのフォームと項目を一致させる形で、axiosからFormDataを投げる。
#余談
この仕組みを作るとき、axiosのbaseURL関係でもハマりました。
上記コードでしれっとthis.$axios.$post(window.location.origin, params)
と書いているところ。
それについては別の記事を書こうと考えています。書きました。(2020.02.12)
#参考
https://www.netlify.com/blog/2018/09/07/how-to-integrate-netlify-forms-in-a-vue-app/
https://qiita.com/yahsan2/items/a70c4c8f617ee9b1f9ff
https://qiita.com/miiina016/items/e86c0bf4f8808dd6b6ae
https://qiita.com/nanaki14/items/007eae905d6305f75f6a
https://qiita.com/tatane616/items/f646e84fe4cdd9eac0de