有15萬開發者使用LeanCloud服務,其中不乏知乎、懂球帝、愛範兒、拉卡拉等知名應用,LeanCloud提供了數據存儲、即時消息……等一站式服務,並從經常使用的用戶管理需求出發,提供了郵箱驗證、短信驗證……等用戶帳戶相關的服務。javascript
爲防止攻擊者惡意發送海量短信形成用戶帳戶損失並影響正常業務,LeanCloud推出了免費圖形校驗碼服務,而且能夠在應用設置中設置「強制短信驗證服務使用圖形校驗碼」。html
Vue是目前使用較普遍的三大前端框架之一,其數據驅動及組件化的特性使得前端開發更爲快捷便利。前端
LeanCloud提供的由客戶發起的短信發送場景主要有用戶驗證、用戶密碼重置,雖然不是不少場景,但若是每一個場景下都單獨進行圖形校驗碼相關開發,則費時費力且對一些須要統一設置的參數調整不夠靈活。java
本文在LeanCloud短信轟炸與圖形校驗碼官方文檔基礎上,從封裝須要出發開發一個簡單的短信圖形驗證Vue組件。前端框架
組件命名爲Mobile,基於Element-UI的Form組件和Input組件進行開發,若是用戶對佈局和樣式有特殊要求,只須要改成本身相應的組件,或者使用原生HTML元素並設置樣式便可,同時須要將Element-UI提供的$message改成本身相應的API調用。框架
開發的Mobile組件用於發送短信驗證碼,所以須要可以輸入手機號碼和圖形校驗碼,並可觸發發送短信的動做,觸發發送短信動做成功後,須要禁用發送短信功能,並進行倒計時,倒計時結束後才能從新發送短信。ide
所以具體的組件行爲主要是如下幾點:函數
其中發送短信的行爲必須調用不一樣場景下的API,所以咱們須要將此按鈕綁定的事件emit到父組件,由父組件決定具體調用哪一個API。組件化
從上述組件行爲出發,分析須要傳入組件的props:佈局
組件的props選項以下:
props: { labelWidth: { type: String, default: '100px' }, value: String, smsSent: Boolean },
組件模板中,與props相關的考量主要有以下三方面:
<el-form :label-width="labelWidth">
。<el-input :value="value" @input="value => $emit('input', value)">
,這樣就能夠實現「v-model透傳」。爲在組件加載時顯示圖形校驗碼,須要在組件的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>