最近看到新拟物风格的倾向,于是手痒难耐,决定尝试实现一个新拟物风格的验证码组件。
实现思路
- 上面是一个显示输入验证码的列表
- 底部是一个不可见的输入框
- 点击输入位置,将不可见的输入框激活
直接上干货
<template>
<view class="yuumi-captcha" @longtap="onPaste" @tap="onPasted">
<view class="captcha-box">
<view v-for="item in maxlength" :key="item" :style="itemStyle"
:class="['captcha-item', { _cursor: focused && item === captcha.length}]"
@tap="autoFocus"
>
{{ captcha.slice(item, item + 1) }}
</view>
</view>
<view class="ghost">
<input :type="type" :maxlength="maxlength" v-model="captcha" :focus="focused" @blur="onBlur">
</view>
</view>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
props: {
// 验证码位数
maxlength: { type: Number, default: 6 },
// 单个输入框的尺寸
size: { type: String, default: '80rpx' },
// 输入框的类型
type: { type: String, default: 'number' },
// 是否启用长按粘贴
pasteEnable: { type: Boolean }
},
data () {
return {
captcha: "",
focused: false,
pasting: false
}
},
computed: {
itemStyle(): string{
return `flex-basis: ${this.size};height: ${this.size};line-height: ${this.size};`
}
},
methods: {
autoFocus() {
if (this.focused || this.pasting) return
this.focused = true
},
onBlur() {
this.focused = false
this.completed()
},
onPaste() {
if (!this.pasteEnable) return
this.pasting = true
uni.getClipboardData({
success: (res: any) => {
this.captcha = (res.data || "").slice(0, 6)
}
})
},
onPasted() {
if (!this.pasting) return
this.$nextTick(() => {
this.pasting = false
this.completed()
})
},
completed() {
if (this.captcha.length === this.maxlength) {
this.$emit("complete", { value: this.captcha })
}
}
}
})
</script>
<style lang="scss" scoped>
.captcha-box {
display: flex;
align-items: center;
justify-content: space-around;
.captcha-item {
position: relative;
flex: 0 0 auto;
text-align: center;
color: #50a684;
background-color: #eaecf1;
border-radius: 8rpx;
box-shadow:
-6rpx -6rpx 18rpx rgba(255, 255, 255, 1),
6rpx 6rpx 18rpx rgba(0, 0, 0, 0.2);
transition: boxShadow 0.3s;
&._cursor::after {
display: block;
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 2px;
height: 16px;
transform: translate3d(-50%, -50%, 0);
background-color: #50a684;
animation: cursor 1s linear infinite;
}
&._cursor {
box-shadow:
-6rpx -6rpx 18rpx rgba(255, 255, 255, 1) inset,
6rpx 6rpx 18rpx rgba(0, 0, 0, 0.2) inset;
}
}
}
.ghost {
width: 0;
height: 0;
overflow: hidden;
}
@keyframes cursor {
0% {
background-color: transparent;
}
50% {
background-color: #50a684;
}
100% {
background-color: transparent;
}
}
</style>
记得将页面背景色设置为
#eaecf1这样效果才能出来