Vue.jsで作成したフォームにreCAPTCHAを組み込みたいと考えました。
組み込むといっても普通のフォームであれば難なくできたのでさして難しく考えていませんでした。動作としては下記のような挙動を実装したいです。
- ページの描画時にreCAPTCHAのウィジェットを表示
- Vue Router等で遷移して戻ってきたときにも描画(何も考えずに埋め込むとこの時描画されない)
- 他の項目もバリデーションが全てOKであれば、reCAPTCHAのチェックボックスにチェックを入れてレスポンスのトークンを取得した時点で
submit
ボタンを有効化する(「レスポンスでトークンを取得」というイベントにどうやってフックし、Vue.js側のメソッドを発火させるのか……) - 2分ほど放置してreCAPTCHAが
expired
(タイムアウト)したら、そのタイミングでフォームデータにセットしたトークンをリセットし、submit
ボタンをdisabledにする(これもイベントへのフックと発火がどうすれば良いのやら)
どれも直感的・自然に「そうあってほしい」という挙動だと思います。が、そのためにはGoogleの外部スクリプトを読み込み、それとVue.jsを連携させる必要があり、そこで四苦八苦。どうにも上手く行く見通しが立ちませんでした。
エラーコードなどでググったり外部スクリプトの読み込み関係を調べたりしていて行き詰ったとき、そもそもとして世の開発者達はどうやっているのかと「Vue.js reCAPTCHA」とググってみたところ……
ライブラリがある……だと……?!
早速今までのコードを投げ捨てて
npm install vue-recaptcha
して試してみることに。
結果。あっけなくできてしまいました。ライブラリ製作者に感謝🙏😇
index.html
<script src="https://www.google.com/recaptcha/api.js?onload=vueRecaptchaApiLoaded&render=explicit" async defer>
</script>
HTMLはサンプル通り。
Vueコンポーネント
<template>
<form @submit.prevent="send">
<vue-recaptcha :sitekey="this.procenv.sitekey" @verify="onVerify" @expired="onExpired"></vue-recaptcha>
<button type="submit" :disabled="this.disabled ? true : false">送信</button>
</form>
</template>
<script>
import VueRecaptcha from 'vue-recaptcha'
export default {
name: 'Form',
components: {
VueRecaptcha
},
data() {
return {
sendflag: null,
recaptcha: {
useflag: false, //reCAPTCHAを使用するかどうするか
setflag: false, //reCAPTCHAに値が入ったかどうか
response: '' //レスポンスのトークン
}
}
},
methods: {
submitEnable() {
//略
if(this.recaptcha.useflag) { //reCAPTCHAあり
if(this.recaptcha.responce !== null && this.recaptcha.responce !== undefined && this.recaptcha.responce.length > 0) { //値がセットされればフラグセット
this.recaptcha.setflag = true
}
}
if(/* 他のバリデーションがOKというフラグ */ && this.recaptcha.setflag) { //全項目がバリデーションOK、かつreCAPTCHAがセット(未使用の場合は最初からtrue)されていれば
this.disabled = false //submitボタンのdisabledを外す
//送信用の値セット
}
else {
this.disabled = true //disabledを付け直す
//送信用の値リセット
}
}
},
onVerify(response) {
this.recaptcha.responce = response //レスポンスのトークンをセット
this.submitEnable() //バリデーションとsubmitボタンを有効にするメソッドを発火
},
onExpired() {
this.recaptcha.responce = '' //レスポンスのトークンを空に戻す
this.recaptcha.setflag = false //フラグを下す
this.disabled = true //submitボタンをdisabledに
},
resetRecaptcha() {
this.$refs.recaptcha.reset() // Direct call reset method
}
}
reCAPTCHA周りのコードを抜き出すとこんな感じ。すごく楽にできました🎉