LeanCloud帶圖形校驗碼的短信發送Vue組件開發

有15萬開發者使用LeanCloud服務,其中不乏知乎、懂球帝、愛範兒、拉卡拉等知名應用,LeanCloud提供了數據存儲、即時消息……等一站式服務,並從經常使用的用戶管理需求出發,提供了郵箱驗證、短信驗證……等用戶帳戶相關的服務。javascript

爲防止攻擊者惡意發送海量短信形成用戶帳戶損失並影響正常業務,LeanCloud推出了免費圖形校驗碼服務,而且能夠在應用設置中設置「強制短信驗證服務使用圖形校驗碼」。html

圖形校驗碼

Vue是目前使用較普遍的三大前端框架之一,其數據驅動及組件化的特性使得前端開發更爲快捷便利。前端

LeanCloud提供的由客戶發起的短信發送場景主要有用戶驗證、用戶密碼重置,雖然不是不少場景,但若是每一個場景下都單獨進行圖形校驗碼相關開發,則費時費力且對一些須要統一設置的參數調整不夠靈活。java

本文在LeanCloud短信轟炸與圖形校驗碼官方文檔基礎上,從封裝須要出發開發一個簡單的短信圖形驗證Vue組件。前端框架

組件命名爲Mobile,基於Element-UI的Form組件和Input組件進行開發,若是用戶對佈局和樣式有特殊要求,只須要改成本身相應的組件,或者使用原生HTML元素並設置樣式便可,同時須要將Element-UI提供的$message改成本身相應的API調用。框架

組件行爲

開發的Mobile組件用於發送短信驗證碼,所以須要可以輸入手機號碼和圖形校驗碼,並可觸發發送短信的動做,觸發發送短信動做成功後,須要禁用發送短信功能,並進行倒計時,倒計時結束後才能從新發送短信。ide

所以具體的組件行爲主要是如下幾點:函數

  • 提供一個輸入手機號的輸入框,該輸入框內容能夠由用戶輸入,也能夠從用戶信息中獲取。
  • 提供一個輸入圖形校驗碼的輸入框。
  • 頁面加載完畢顯示圖形校驗碼。
  • 提供一個發送短信的按鈕,用戶點擊發送短信的按鈕,校驗圖形校驗碼,若校驗經過,使用手機號碼,並以圖形校驗碼校驗返回的validataionToken做爲option參數發送短信。
  • 短信發送成功,禁用發送短信的按鈕,啓動定時器進行倒計時,倒計時結束後恢復發送短信的按鈕。
  • 組件使用Element-UI的Form組件的佈局,須要考慮el-form的labelWidth標籤寬度設置與父組件中的el-form匹配。

其中發送短信的行爲必須調用不一樣場景下的API,所以咱們須要將此按鈕綁定的事件emit到父組件,由父組件決定具體調用哪一個API。組件化

組件props

從上述組件行爲出發,分析須要傳入組件的props:佈局

  • 表示手機號碼的屬性。咱們發送短信驗證碼的目的是最終用於後續的驗證或密碼重置操做,而且有可能還須要將手機號碼保存到用戶屬性中,所以該屬性能夠從外部傳入,而且可以在組件內部修改後返回父組件,所以該屬性必須是雙向綁定的,Vue組件中雙向綁定的屬性有兩種,一是自定義v-model,屬性名必須是value,一是能夠使用.sync修飾符綁定的屬性,這裏將手機號碼屬性設置爲Mobile組件的v-model屬性,屬性名爲value。
  • 通知Mobile組件短信已發送的屬性。屬性名爲smsSent,類型爲Boolean,以禁用發送短信的按鈕,並啓動倒計時。
  • el-form的labelWidth屬性。設置默認值,並接受來自父組件中傳遞的數據以保持與父組件中其餘元素/組件佈局一致。

組件的props選項以下:

props: {
  labelWidth: {
    type: String,
    default: '100px'
  },
  value: String,
  smsSent: Boolean
},

組件模板中,與props相關的考量主要有以下三方面:

  • 組件的根元素是一個el-form組件,其label-width屬性綁定到來自父組件的labelWidth屬性,<el-form :label-width="labelWidth">
  • 手機號碼輸入框使用el-input組件,綁定到value屬性,要實現雙向綁定,不能直接使用v-model進行數據綁定,而是要將v-model綁定轉換爲v-bind:value屬性綁定和@input事件綁定,<el-input :value="value" @input="value => $emit('input', value)">,這樣就能夠實現「v-model透傳」。
  • (間接)發送短信按鈕的禁用狀態。發送短信按鈕的禁用狀態由倒計時的計數器組件data數據觸發,當該數據不爲0時,發送短信的按鈕禁用。倒計時觸發方式是經過父組件中綁定的smsSent屬性,所以須要在子組件中watch該屬性,並在該值爲真是設置倒計時計數器,並經過setInterval進行倒計時。

圖形校驗碼加載

爲在組件加載時顯示圖形校驗碼,須要在組件的mounted生命週期鉤子中調用LeanCloud的API。

在AV.Captcha.request()的回調中綁定校驗碼輸入框、圖形校驗碼元素以及發送短信按鈕元素,綁定參數對象的三個屬性都可以是表示元素id的string或實際HTMLElement,因爲咱們建立的是Vue組件,所以直接使用組件的$refs屬性來指定實際HTMLElement,須要注意的是,el-input中input元素是ref的$el屬性的children[0],而el-button中button元素是ref的$el。

綁定函數還須要傳入第二個參數,這是一個含有success和error方法的對象,用於提供圖形校驗碼校驗成功和失敗的操做。

發送短信驗證碼

發送短信驗證碼在傳遞的第二個參數對象的success方法中進行,在這裏,咱們首先更新組件的smsSent屬性爲false,這樣,當在父組件中實際完成短信發送以後設置smsSent爲true時纔會觸發針對smsSent屬性的watcher,同時,須要注意在父組件中綁定smsSent屬性時,必須使用.sync修飾符。而後向父組件emit自定義sendSmsCode事件,並將success回調時的validateToken參數透傳過去。

mounted () {
  this.$emit('update:smsSent', false)
  AV.Captcha.request().then((captcha) => {
    captcha.bind({
      textInput: this.$refs.captcha.$el.children[0],
      image: this.$refs.captchaImage,
      verifyButton: this.$refs.sendSms.$el
    }, {
      success: (validateToken) => {
        this.$emit('sendSmsCode', validateToken)
      },
      error: () => {
        this.$message.error('請輸入正確的圖形校驗碼!')
      }
    })
  })
}

組件使用

首先在父組件的組件選項中添加包含Mobile組件的components,而後在模板中添加mobile組件。

<mobile v-model="mobileForm.mobile"
        :sms-sent.sync="mobileForm.smsSent"
        @sendSmsCode="sendSms"></mobile>

其中綁定sendSmsCode事件的方法以下:

sendSms (validateToken) {
  this.sendSmsCode({
    mobile: this.mobileForm.mobile,
    validateToken
  }).then(() => {
    this.mobileForm.smsSent = true
  })
},

完整組件代碼

<template>
  <el-form class="mobile-form"
           :label-width="labelWidth"
           ref="mobile-form">
    <el-form-item label="手機號碼" prop="mobile">
      <el-input :value="value"
                @input="value => $emit('input', value)"
                :maxlength="11"
                type="tel">
      </el-input>
    </el-form-item>
    <el-form-item label="圖形校驗碼">
      <el-input type="text" ref="captcha"></el-input>
      <img ref="captchaImage">
    </el-form-item>
    <el-form-item>
      <el-button type="info"
                 ref="sendSms"
                 :disabled="smsCodeCountingDown > 0 ||
                             value.length !== 11">
        發送驗證碼
      </el-button>
      <span v-if="smsCodeCountingDown > 0">
                  {{smsCodeCountingDown}} 秒後從新發送
                </span>
    </el-form-item>
  </el-form>
</template>

<script>
  import AV from 'leancloud-storage'

  export default {
    data () {
      return {
        smsCodeCountingDown: 0
      }
    },
    props: {
      labelWidth: {
        type: String,
        default: '100px'
      },
      value: String,
      smsSent: Boolean
    },
    watch: {
      smsSent (val) {
        if (val) {
          this.smsCodeCountingDown = 30
          let countingDownInterval = setInterval(() => {
            this.smsCodeCountingDown--
            if (this.smsCodeCountingDown === 0) {
              clearInterval(countingDownInterval)
            }
          }, 1000)
        }
      }
    },
    mounted () {
      AV.Captcha.request().then((captcha) => {
        captcha.bind({
          textInput: this.$refs.captcha.$el.children[0],
          image: this.$refs.captchaImage,
          verifyButton: this.$refs.sendSms.$el
        }, {
          success: (validateToken) => {
            this.$emit('update:smsSent', false)
            this.$emit('sendSmsCode', validateToken)
          },
          error: () => {
            this.$message.error('請輸入正確的圖形校驗碼!')
          }
        })
      })
    }
  }
</script>

<style scoped>
  .sms-code-form {
    width: 360px;
  }
</style>
相關文章
相關標籤/搜索