2018-03-26 16:04:04 +08:00
|
|
|
<template>
|
|
|
|
<div class="md-captcha" v-show="isView || value || visible">
|
|
|
|
<template v-if="isView">
|
|
|
|
<div class="md-captcha-content">
|
|
|
|
<h2 class="md-captcha-title" v-if="title" v-text="title"></h2>
|
2018-04-11 15:22:40 +08:00
|
|
|
<div class="md-captcha-message">
|
2018-03-26 16:04:04 +08:00
|
|
|
<slot></slot>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<md-codebox
|
|
|
|
ref="codebox"
|
|
|
|
v-model="code"
|
|
|
|
:maxlength="maxlength"
|
|
|
|
:system="system"
|
|
|
|
:mask="mask"
|
|
|
|
@submit="$_onSubmit"
|
2018-08-27 19:17:20 +08:00
|
|
|
:closable="false"
|
|
|
|
:isView="true"
|
|
|
|
:justify="true"
|
|
|
|
:autofocus="false"
|
2018-03-26 16:04:04 +08:00
|
|
|
/>
|
2018-08-27 19:17:20 +08:00
|
|
|
<footer class="md-captcha-footer">
|
|
|
|
<div class="md-captcha-error" v-text="errorMsg"></div>
|
|
|
|
<button
|
|
|
|
class="md-captcha-btn"
|
|
|
|
v-if="count"
|
|
|
|
v-text="countBtnText"
|
|
|
|
:disabled="this.isCounting"
|
|
|
|
@click="$_onResend"
|
|
|
|
></button>
|
|
|
|
</footer>
|
2018-03-26 16:04:04 +08:00
|
|
|
</template>
|
|
|
|
<template v-else>
|
|
|
|
<md-dialog
|
|
|
|
:value="value"
|
|
|
|
:closable="true"
|
|
|
|
:appendTo="false"
|
|
|
|
position="center"
|
|
|
|
@input="$_onInput"
|
|
|
|
@show="$_onShow"
|
|
|
|
@hide="$_onHide"
|
|
|
|
>
|
|
|
|
<div class="md-captcha-content">
|
|
|
|
<h2 class="md-captcha-title" v-if="title" v-text="title"></h2>
|
2018-04-11 15:22:40 +08:00
|
|
|
<div class="md-captcha-message">
|
2018-03-26 16:04:04 +08:00
|
|
|
<slot></slot>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<md-codebox
|
|
|
|
ref="codebox"
|
|
|
|
v-model="code"
|
|
|
|
:maxlength="maxlength"
|
|
|
|
:system="system"
|
|
|
|
:closable="false"
|
|
|
|
:mask="mask"
|
2018-08-27 19:17:20 +08:00
|
|
|
:justify="true"
|
2018-03-26 16:04:04 +08:00
|
|
|
:autofocus="false"
|
|
|
|
@submit="$_onSubmit"
|
|
|
|
/>
|
2018-08-27 19:17:20 +08:00
|
|
|
<footer class="md-captcha-footer">
|
|
|
|
<div class="md-captcha-error" v-text="errorMsg"></div>
|
|
|
|
<button
|
|
|
|
class="md-captcha-btn"
|
|
|
|
v-if="count"
|
|
|
|
v-text="countBtnText"
|
|
|
|
:disabled="this.isCounting"
|
|
|
|
@click="$_onResend"
|
|
|
|
></button>
|
|
|
|
</footer>
|
2018-03-26 16:04:04 +08:00
|
|
|
</md-dialog>
|
|
|
|
</template>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
import Dialog from '../dialog'
|
|
|
|
import Codebox from '../codebox'
|
|
|
|
import Button from '../button'
|
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'md-captcha',
|
|
|
|
|
|
|
|
components: {
|
|
|
|
[Dialog.name]: Dialog,
|
|
|
|
[Codebox.name]: Codebox,
|
|
|
|
[Button.name]: Button,
|
|
|
|
},
|
|
|
|
|
|
|
|
props: {
|
|
|
|
title: {
|
|
|
|
type: String,
|
|
|
|
},
|
|
|
|
value: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
maxlength: {
|
|
|
|
type: [Number, String],
|
|
|
|
default: 4,
|
|
|
|
},
|
|
|
|
mask: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
system: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
2018-05-20 21:33:27 +08:00
|
|
|
autoCountdown: {
|
|
|
|
type: Boolean,
|
|
|
|
default: true,
|
|
|
|
},
|
2018-03-26 16:04:04 +08:00
|
|
|
appendTo: {
|
|
|
|
default: () => document.body,
|
|
|
|
},
|
|
|
|
count: {
|
|
|
|
type: Number,
|
|
|
|
default: 60,
|
|
|
|
},
|
2018-05-20 21:33:27 +08:00
|
|
|
countNormalText: {
|
|
|
|
type: String,
|
|
|
|
default: '发送验证码',
|
|
|
|
},
|
|
|
|
countActiveText: {
|
|
|
|
type: String,
|
|
|
|
default: '{$1}秒后重发',
|
|
|
|
},
|
2018-03-26 16:04:04 +08:00
|
|
|
isView: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
code: '',
|
|
|
|
visible: false,
|
2018-04-11 15:22:40 +08:00
|
|
|
errorMsg: '',
|
2018-03-26 16:04:04 +08:00
|
|
|
isCounting: false,
|
|
|
|
firstShown: false,
|
2018-05-20 21:33:27 +08:00
|
|
|
countBtnText: this.countNormalText,
|
2018-03-26 16:04:04 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
watch: {
|
|
|
|
value(val) {
|
|
|
|
if (val) {
|
|
|
|
this.code = ''
|
|
|
|
if (!this.firstShown) {
|
|
|
|
this.firstShown = true
|
2018-05-20 21:33:27 +08:00
|
|
|
this.$_onResend()
|
2018-03-26 16:04:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2018-04-11 15:22:40 +08:00
|
|
|
code(val) {
|
|
|
|
if (val && this.errorMsg) {
|
|
|
|
this.errorMsg = ''
|
|
|
|
}
|
|
|
|
},
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
if (this.appendTo && !this.isView) {
|
|
|
|
this.appendTo.appendChild(this.$el)
|
|
|
|
}
|
2018-05-20 21:33:27 +08:00
|
|
|
if (this.value || this.isView) {
|
2018-03-26 16:04:04 +08:00
|
|
|
this.firstShown = true
|
2018-05-20 21:33:27 +08:00
|
|
|
this.$_onResend()
|
2018-03-26 16:04:04 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-04-18 15:05:47 +08:00
|
|
|
beforeDestroy() {
|
|
|
|
if (this.appendTo && !this.isView) {
|
|
|
|
this.appendTo.removeChild(this.$el)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-03-26 16:04:04 +08:00
|
|
|
methods: {
|
|
|
|
// MARK: events handler, 如 $_onButtonClick
|
|
|
|
$_onInput(val) {
|
|
|
|
this.$emit('input', val)
|
|
|
|
},
|
|
|
|
$_onShow() {
|
|
|
|
this.visible = true
|
|
|
|
this.$refs.codebox.focus()
|
|
|
|
this.$emit('show')
|
|
|
|
},
|
|
|
|
$_onHide() {
|
|
|
|
this.visible = false
|
|
|
|
this.$refs.codebox.blur()
|
|
|
|
this.$emit('hide')
|
|
|
|
},
|
|
|
|
$_onSubmit(code) {
|
|
|
|
this.$emit('submit', code)
|
|
|
|
},
|
2018-05-20 21:33:27 +08:00
|
|
|
$_onResend() {
|
|
|
|
if (this.autoCountdown) {
|
|
|
|
this.countdown()
|
|
|
|
}
|
|
|
|
this.$emit('send', this.countdown)
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
// MARK: public methods
|
|
|
|
countdown() {
|
2018-04-24 22:49:00 +08:00
|
|
|
if (!this.count) {
|
|
|
|
return
|
|
|
|
}
|
2018-03-26 16:04:04 +08:00
|
|
|
clearInterval(this.__counter__)
|
|
|
|
let i = this.count - 1
|
|
|
|
this.isCounting = true
|
2018-05-20 21:33:27 +08:00
|
|
|
this.countBtnText = this.countActiveText.replace('{$1}', i)
|
2018-04-23 17:33:32 +08:00
|
|
|
/* istanbul ignore next */
|
2018-03-26 16:04:04 +08:00
|
|
|
this.__counter__ = setInterval(() => {
|
2018-05-20 21:33:27 +08:00
|
|
|
if (i === 1) {
|
2018-03-26 16:04:04 +08:00
|
|
|
this.resetcount()
|
|
|
|
} else {
|
|
|
|
i--
|
2018-05-20 21:33:27 +08:00
|
|
|
this.countBtnText = this.countActiveText.replace('{$1}', i)
|
2018-03-26 16:04:04 +08:00
|
|
|
}
|
|
|
|
}, 1000)
|
|
|
|
},
|
|
|
|
resetcount() {
|
|
|
|
this.isCounting = false
|
2018-05-20 21:33:27 +08:00
|
|
|
this.countBtnText = this.countNormalText
|
2018-03-26 16:04:04 +08:00
|
|
|
clearInterval(this.__counter__)
|
|
|
|
},
|
2018-04-11 15:22:40 +08:00
|
|
|
setError(msg) {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
this.errorMsg = msg
|
|
|
|
this.code = ''
|
|
|
|
})
|
|
|
|
},
|
2018-03-26 16:04:04 +08:00
|
|
|
},
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="stylus">
|
2018-08-27 19:17:20 +08:00
|
|
|
.md-captcha
|
|
|
|
.md-dialog
|
2018-09-13 16:14:47 +08:00
|
|
|
.md-popup.with-mask
|
|
|
|
z-index captcha-zindex
|
2018-08-27 19:17:20 +08:00
|
|
|
.md-dialog-body
|
|
|
|
padding 60px
|
|
|
|
.md-dialog-content
|
|
|
|
margin-bottom number-keyboard-height
|
|
|
|
|
|
|
|
.md-captcha-content
|
|
|
|
font-size captcha-font-size
|
|
|
|
color captcha-color
|
|
|
|
text-align center
|
|
|
|
line-height 1.2
|
|
|
|
margin-bottom 50px
|
|
|
|
|
|
|
|
.md-captcha-title
|
|
|
|
color captcha-title-color
|
|
|
|
font-size captcha-title-font-size
|
|
|
|
font-weight normal
|
|
|
|
line-height 1.15
|
|
|
|
margin 0 0 16px 0
|
|
|
|
|
|
|
|
.md-captcha-footer
|
|
|
|
margin-top 28px
|
|
|
|
display flex
|
|
|
|
font-size captcha-footer-font-size
|
|
|
|
justify-content space-between
|
|
|
|
align-items center
|
|
|
|
overflow hidden
|
|
|
|
|
|
|
|
.md-captcha-error
|
|
|
|
flex 1 1 0%
|
|
|
|
color captcha-error-color
|
|
|
|
|
|
|
|
.md-captcha-btn
|
|
|
|
display inline-block
|
|
|
|
color captcha-btn-color
|
|
|
|
font-size captcha-footer-font-size
|
|
|
|
padding 0
|
|
|
|
margin 0 0 0 12px
|
|
|
|
border 0
|
|
|
|
border-radius 0
|
|
|
|
background none
|
|
|
|
&:disabled
|
|
|
|
color color-text-disabled
|
2018-03-26 16:04:04 +08:00
|
|
|
</style>
|