【问题标题】:Vue.js google reCaptcha callbackVue.js google reCaptcha 回调
【发布时间】:2017-10-08 22:59:46
【问题描述】:

我正在尝试让 recaptcha 回调在组件中与 vue.js 一起使用。验证码本身确实有效,但不是我在 data-callback 属性中定义的回调。

我已经尝试了所有我能想到的方法,但我仍然收到 ReCAPTCHA couldn't find user-provided function: dothisthat 错误。

这是组件

<script>
    function dothisthat (){
            alert(312);
        }
</script>

<template>
    <div class="well main-well">
        <h4>Captcha</h4>
        <p class="small">You must complete the captcha to finish your booking.</p>
        <div id="captcha-wrapper">
            <div class="g-recaptcha" :data-sitekey="captchaKey" data-callback="dothisthat"></div>
        </div>
    </div>
</template>
<script>
     function dothisthat (){
        alert(123);
    }
    import * as filters from '../../../filters';
    import Translation from '../../../Translation';

    export default {
        name: 'Captcha',
        props: {
        },
        computed: {
            captchaKey: function() {
                return this.$store.getters.captcha;
            }
        },
        methods: {
            dothisthat: function(){
                return function() {
                    console.log("123");
                };
            }
        },
        mounted(){

            function dothisthat() {
                alert(123);
            }
            $(function() {
                function dothisthat() {
                    alert(123);
                }
            });
        }
    }
</script>

没有一个dothisthat 函数被调用。 我做错了什么?

【问题讨论】:

  • 试试:data-callback="dothisthat"?
  • 返回 ReCAPTCHA 找不到用户提供的函数:function boundFn(a) { var l = arguments.length;返回 l ? l > 1 ? fn.apply(ctx, arguments) : fn.call(ctx, a) : fn.call(ctx) }

标签: javascript vue.js recaptcha


【解决方案1】:

我也遇到过这个问题,我花了 2 天时间才解决。

所以我将在这里提供一个从头开始逐步将 recaptcha 与 vue.js 集成的一般答案,以便为将来处于相同情况的人提供一个简单的指南(我假设使用 vue-cli在这里)。

注意:我在这里使用的是不可见的recaptcha,但过程与普通的非常相似

第 1 步:

将 recaptcha javascript api 添加到您的 index.html

index.html

<script src="https://www.google.com/recaptcha/api.js" async defer></script>

第 2 步:

制作一个名为 Recaptcha 的组件或任何您想调用的名称(制作一个组件将使您的代码更易于阅读、更易于维护,并且如果需要,更容易将 recaptcha 添加到多个页面)

Recaptcha.vue

<template>
  <div 
  id="g-recaptcha"
  class="g-recaptcha"
  :data-sitekey="sitekey">
  </div>
</template>

<script>
export default {
  data () {
    return {
      sitekey: '6LfAEj0UAAAAAFTGLqGozrRD8ayOy*********',
      widgetId: 0
    }
  },
  methods: {
    execute () {
      window.grecaptcha.execute(this.widgetId)
    },
    reset () {
      window.grecaptcha.reset(this.widgetId)
    },
    render () {
      if (window.grecaptcha) {
        this.widgetId = window.grecaptcha.render('g-recaptcha', {
          sitekey: this.sitekey,
          size: 'invisible',
          // the callback executed when the user solve the recaptcha
          callback: (response) => {
            // emit an event called verify with the response as payload
            this.$emit('verify', response)
            // reset the recaptcha widget so you can execute it again
            this.reset() 
          }
        })
      }
    }
  },
  mounted () {
    // render the recaptcha widget when the component is mounted
    this.render()
  }
}
</script>

第 3 步:

导入 recaptcha 组件并将其添加到您的页面(父组件)。

page.vue

<template>
  <div>
    <h1>Parent component (your page)</h1>
    <button @click="executeRecaptcha">execute recaptcha</button>
    <!-- listen to verify event emited by the recaptcha component -->
    <recaptcha ref="recaptcha" @verify="submit"></recaptcha>
  </div>
</template>

<script>
import Recaptcha from 'recaptcha'
export default {
  components: {
    Recaptcha
  },
  methods: {
    // send your recaptcha token to the server to verify it
    submit (response) {
      console.log(response)
    },
    // execute the recaptcha widget
    executeRecaptcha () {
      this.$refs.recaptcha.execute()
    }
  }
}
</script>

【讨论】:

  • 只是一个附加功能,如果你推迟了recaptcha脚本,你可以使用recaptcha渲染功能的重试机制。
  • 你为什么同时使用id="g-recaptcha"class="g-recaptcha"?你可以只使用id 属性id="g-recaptcha" 而不使用class 属性吗?
  • @stanimirsp 您可以删除class,但需要id 才能在window.grecaptcha.render 函数中引用它。我不知道为什么我在那里添加了这个类 LOL。我想我只是从这样的文档中复制了代码。
  • 感谢 Abdelaziz Mokhnache,这是最好的解决方案。非常有组织和动态。再次感谢伙计。
【解决方案2】:

我没有使用组件,但是我遇到了同样的问题,最后我是这样解决的:

HTML

<div id="recaptcha" class="g-recaptcha"></div>
<button id="submit" @click="validate">Submit</button>
<script src="https://www.google.com/recaptcha/api.js?render=explicit" async defer></script>

JS

// ...
mounted: function() {
    this.initReCaptcha();
},
methods: {
    initReCaptcha: function() {
        var self = this;
        setTimeout(function() {
            if(typeof grecaptcha === 'undefined') {
                self.initReCaptcha();
            }
            else {
                grecaptcha.render('recaptcha', {
                    sitekey: 'SITE_KEY',
                    size: 'invisible',
                    badge: 'inline',
                    callback: self.submit
                });
            }
        }, 100);
    },
    validate: function() {
        // your validations...
        // ...
        grecaptcha.execute();
    },
    submit: function(token) {
        console.log(token);
    }
},

【讨论】:

  • initReCaptcha 方法成功了!谢谢。我没有在recaptcha成功回调上提交,而是在回调中设置了我的表单变量,所以我将它发布到我的api。回调:函数(响应){ self.form.g_recaptcha_response = response; }
  • 应该是window.grecaptcha。不是吗?
  • 使用 setTimeout 进行依赖加载是 moveton。你需要使用加载回调、事件或承诺。否则网络延迟无论如何都会破坏您的应用程序。即使延迟 100 毫秒
【解决方案3】:

如果您只是在寻找recaptcha 的响应值以便在服务器端对其进行验证,一个简单的解决方案是将您的recaptcha 元素放在一个表单中并从提交@987654321 的目标元素中获取响应值@。

<form class="container"
  @submit="checkForm"
  method="post"
>

... // other elements of your form 

<div class="g-recaptcha" data-sitekey="your_site_key"></div>

<p>
    <input class="button" type="submit" value="Submit">
</p>
</form>

checkForm方法中:

methods : {
        checkForm: function (event) {
            recaptcha_response_value = event.target['g-recaptcha-response'].value

           ...
         }

【讨论】:

    【解决方案4】:

    我在使用其他解决方案时遇到的问题是,当 ReCaptcha 未完全加载时,它有时会尝试执行 window.grecaptcha.render。根据他们的documentation 进行检查的唯一方法是使用onload 方法。

    下面这个例子是我使用它的方式,当然你可以自定义你对回调的操作。

    ReCaptcha.Vue:

    <template>
        <div ref="grecaptcha"></div>
    </template>
    
    <script>
        export default {
    
            props: ['sitekey'],
    
            methods: {
    
                loaded(){
    
                    window.grecaptcha.render(this.$refs.grecaptcha, {
                        sitekey: this.sitekey,
                        callback: (response) => {
    
                            this.$emit('input', response);
    
                        },
                    });
    
                },
    
            },
    
            mounted(){
    
                /**
                 * Set Recapchat loaded function
                 */
                window.ReCaptchaLoaded = this.loaded;
    
                /**
                 * Set Recaptcha script in header
                 */
                var script = document.createElement('script');
                script.src = 'https://www.google.com/recaptcha/api.js?onload=ReCaptchaLoaded&render=explicit';
                document.head.appendChild(script);
    
            }
    
        }
    </script>
    

    用法

    <ReCaptcha sitekey="KEY" v-model="fields.g_recaptcha_response.value" />
    

    【讨论】:

    • 我遇到了一个问题,它仍然产生错误“未捕获的 TypeError:grecaptcha.render 不是函数”,所以我添加了 script.async = true 和 script.defer = true 并消除了它
    • grecaptcha.render is not a function 问题的解决方案是 window.grecaptcha 中有一个可用的 ready 方法,您可以使用回调函数调用它 - 所以,首先您等待 onload 完成,然后然后你等待ready函数给你回电。我想我会添加一个答案...
    • 我得到ERROR for site owner: Invalid key type,即使我的密钥在通过像这样&lt;script id='recaptcha' src="https://www.google.com/recaptcha/api.js?render={{ CAPTCHA_SITEKEY }}"&gt;&lt;/script&gt; 这样的模板在标题中使用时工作正常
    【解决方案5】:

    最简单的解决方案:

    HTML:

    <div class="g-recaptcha" data-sitekey="key" data-callback="myRecaptchaMethod">
    </div>
    

    Vue:

    methods: {
        myRecaptchaMethod: function(response) {
            console.log(response); 
            // this is google's code verifying the user is human'
            // that you check with google on the backend.
        }
    }
    
    mounted: function() {
        window.myRecaptchaMethod = this.myRecaptchaMethod;
    }
    

    完成

    【讨论】:

      【解决方案6】:

      前面的答案很好,但我想要一个不关心脚本和异步加载的插入式组件,所以我自己做了一个简单的组件。

      TL;DR

      1. 看这个要点
      2. Recaptcha2.vue 文件复制到您的源代码树中
      3. &lt;recaptcha2&gt; 添加到您的 Vue 应用中

      详情

      https://gist.github.com/aellerton/92f33cef04a1df76636a658571e07724

      加载recaptcha 脚本并进行初始化需要花费一些时间。正如我在对这个问题的另一个答案的评论中提到的,首先是 onload 回调然后 grecaptcha.ready 函数可以调用你的函数说“是的,一切都准备好了立即致电render”。

      Google 提供该功能非常好,尽管我无法在任何地方找到它的文档。

      将所有内容封装在一个函数中看起来像这样(它是 TypeScript,但你可以删除类型的东西,它只是 JavaScript):

      function loadRecaptcha(callback: () => void) {
        let win = window as any
        if (win && !win.grecaptcha) {
          let recaptchaScript = document.createElement('script')
          document.head.appendChild(recaptchaScript)
          recaptchaScript.onload = () => {
            // At this point the recaptcha script has loaded but the
            // code in it as not completed loading. Fortunately there's
            // a "ready" function in there that can tell us when it's done.
            let win = window as any
            win.grecaptcha.ready(() => {
              callback()
            })
          }
          recaptchaScript.setAttribute('src', 'https://www.google.com/recaptcha/api.js')
        } else {
          callback()
        }
      }
      

      然后组件本身就简单多了——它在mounted() 中调用该函数并运行grecaptcha.render 以动态创建recaptcha。不需要全局函数。

      以最简单的形式使用组件,如下所示:

        <div>
          <p>A tiny recaptcha demo</p>
          <recaptcha2 @change="robotChange"></recaptcha2>
          <p>Is human? {{isHuman}}
          <button :disabled="isSendDisabled">Send now</button>
        </div>
      

      更多详情the gist

      【讨论】:

        【解决方案7】:

        只需使用 vue-recaptcha https://www.npmjs.com/package/vue-recaptcha

        npm install --save vue-recaptcha

        <vue-recaptcha
          @verify="onVerify"
          :sitekey="this.key"
          :loadRecaptchaScript='true' // vue-recaptcha will inject <script src='//google.com/recaptcha/api.js'></script> in head
          @expired="onCaptchaExpired"
          ref="recaptcha"
         ></vue-recaptcha>
        
        import VueRecaptcha from 'vue-recaptcha';
        
        export default {
          components: {
            VueRecaptcha
          },
          data() {
            return {
              user: {
                login: null,
                recaptcha: null,
              },
              key: // your sitekey
            };
          },     
          methods: {
            onVerify(response) {
              this.user.recaptcha = response;
            },
            onCaptchaExpired: function () {
              this.$refs.recaptcha.reset();
            }
          }
        };
        </script> 
        

        【讨论】:

        • 上述解决方案是使用recaptcha 最简单的方法,但如果您尝试使用:siteKey 传递sitekey,这将不起作用。 vue-recaptcha 标签接受siteKey 属性,即没有:,因此您不能动态传递siteKey。 Abdelaziz Mokhnache 解决方案看起来更有前途和有条理。会试试看。
        • 不,vue-recaptcha 接受 :sitekey 和 :
        • 不知道为什么,但这对我没有用 :( . Abdelaziz Mokhnache 解决方案,很有魅力
        【解决方案8】:
        in Vue Component : 
        

        在模板中:html

        <template>
        <form @submit.prevent="onSubmit">
            <div class="form-group row">
                <label for="email" class="col-sm-4 col-form-label text-md-right">Email : </label>
        
                <div class="col-md-6">
                    <input v-model="email" id="email"  type="email" class="form-control"  value="" required autofocus>
        
        
                    <span class="invalid-feedback" role="alert">
                                            <strong></strong>
                                        </span>
        
                </div>
            </div>
        
            <div class="form-group row">
                <label for="password" class="col-md-4 col-form-label text-md-right">
                    Password :
                </label>
        
                <div class="col-md-6">
                    <input v-model="password" id="password" type="password" class="form-control"  required>
        
        
                    <span class="invalid-feedback" role="alert">
                                            <strong></strong>
                                        </span>
        
                </div>
            </div>
        
            <div class="form-group row">
                <div class="col-md-6 offset-md-4">
                    <div class="form-check">
        
                        <input class="form-check-input" type="checkbox" id="remember" v-model="remember">
        
                        <label class="form-check-label" for="remember">
                           Remember me
                        </label>
                        <div id="recaptcha" class="g-recaptcha" data-sitekey="6LehfpsUAAAAAIf3hvWNrGvat8o4lypZh_p6snRH"></div>
                    </div>
                </div>
            </div>
        
            <div class="form-group row mb-0">
                <div class="col-md-8 offset-md-4">
                    <a href="" class="btn btn-danger">Login with google</a>
                    <button type="submit" class="btn btn-primary">
                        Login
                    </button>
        
                    <a class="btn btn-link" href="">
                        Forgot Your Password?
                    </a>
                </div>
            </div>
        </form>
        

        和javascript:

        <script>
        import swal from 'sweetalert';
        export default {
           data(){
        
               return {
                   email: '',
                   password: '',
                   remember: ''
               }
        
           },
            mounted: function() {
                this.initReCaptcha();
            },
            methods: {
                onSubmit(event) {
        
                    let recaptcha_response_value = event.target['g-recaptcha-response'].value;
                    console.log(recaptcha_response_value);
                    let formData = new FormData();
                    formData.append('email' , this.email);
                    formData.append('password' , this.password);
                    formData.append('remember' , this.remember);
                    formData.append('g-recaptcha-response' , recaptcha_response_value);
                    axios.post('/login' , formData)
                        .then(
                            function(res){
                                swal('ورود شما موفقیت آمیز بود');
                            }
                        )
                        .catch(function(err){
                            swal('ایمیل یا کلمه عبور اشتباه است یا اینکه هنوز ثبت نام نکرده اید');
                            console.log(err);
                        });
        
                }
            }
        
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-03-02
          • 2018-08-05
          • 1970-01-01
          • 2022-01-19
          • 2016-05-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多