撸一个Vue手势验证码组件

手势验证码VAPTCHA

这是一种绘制轨迹进行人机的验证码,官网称为手势验证码。以下为官网说明:

VAPTCHA是“Variation Analysis based Public Turing Test to Tell Computers and Humans Apart”(基于变量分析来区分人类和计算机的图灵测试程序)的缩写,又称为手势验证码,一种基于人工智能和大数据的人机验证解决方案 。相对于传统验证码,VAPTCHA更加简单和安全。

使用方式

使用文档中介绍了3种模式,点击式、嵌入式和隐藏式。其中隐藏式需要vip才能使用,并且使用方式与其他两种不同,这里就只针对点击式、嵌入式编写组件,两种方式的配置大致相同。

使用验证码之前我们需要先在官网注册并创建一个验证单元,创建之后可以获取到一个vidkey,这个vid就是用于前端创建验证码的重要参数。在创建验证单元的时候要填域名,这里需要注意的是,这里可以填ip,所填写的域名需要与你的使用验证码的地址一致。

这里我在codepen上写了一个实例,因为结果域名是codepen.io所以这里创建验证单元时域名就填这个了。

开始动手

创建组件Vaptcha.vue,文档中提供了一个预加载动画,这里直接复制过来用。

初始化验证码需要先加载https://cdn.vaptcha.com/v2.js,但只需要加载一次就行了,所以写一个加载脚本的函数loadV2Script,返回一个Promise对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
loadV2Script() {
if (typeof window.vaptcha === 'function') { //如果已经加载就直接放回
return Promise.resolve()
} else {
return new Promise(resolve => {
var script = document.createElement('script')
script.src = 'https://cdn.vaptcha.com/v2.js'
script.async = true
script.onload = script.onreadystatechange = function () {
if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') {
resolve()
script.onload = script.onreadystatechange = null
}
}
document.getElementsByTagName("head")[0].appendChild(script)
})
}
}

因为加载验证码需要先获取容器,所以我们在mounted里面来初始化验证按钮,这里默认会加载点击式。

1
2
3
4
5
6
7
8
9
10
11
mounted() {
this.loadV2Script().then(() => {
window.vaptcha({
vid: '5b68f7bffc650e121c835ffc',
container: this.$refs.vaptcha
}).then(obj => {
this.$emit('input', obj)
obj.render() //渲染按钮
})
})
},

到这里就已经完成了组件的编写,然后就是一些优化,使用props为组件添加参数,完整代码如下。

具体的使用实例可以参考我在codepen上面的示例,地址:https://codepen.io/insertsweat/pen/WKgMLJ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<template>
<div ref="vaptcha" style="width: 300pxheight: 36px">
<div class="vaptcha-init-main">
<div class="vaptcha-init-loading">
<a href="https: //www.vaptcha.com/" target="_blank"><img src="https: //cdn.vaptcha.com/vaptcha-loading.gif"/></a>
<span class="vaptcha-text">VAPTCHA启动中...</span>
</div>
</div>
</div>
</template>

<script>
const extend = function(to, _from) {
for (const key in _from) {
to[key] = _from[key]
}
return to
}

export default {
props: {
type: {
type: String,
default: 'click'
},
scene: {
type: String,
default: ''
},
vpStyle: {
type: String,
default: 'dark'
},
color: {
type: String,
color: '#3C8AFF'
},
lang: {
type: String,
default: 'zh-CN'
},
},
mounted() {
var config = extend({
vid: '5b68f7bffc650e121c835ffc',
container: this.$refs.vaptcha,
style: this.vpStyle
}, this.$props)
this.loadV2Script().then(() => {
window.vaptcha().then(obj => {
this.$emit('input', obj)
obj.render()
})
})
},
methods: {
loadV2Script() {
if (typeof window.vaptcha === 'function') { //如果已经加载就直接放回
return Promise.resolve()
} else {
return new Promise(resolve => {
var script = document.createElement('script')
script.src = 'https://cdn.vaptcha.com/v2.js'
script.async = true
script.onload = script.onreadystatechange = function() {
if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') {
resolve()
script.onload = script.onreadystatechange = null
}
}
document.getElementsByTagName("head")[0].appendChild(script)
})
}
}
}
}
</script>

<style>
.vaptcha-init-main {
display: table;
width: 100%;
height: 100%;
background-color: #EEEEEE;
}

.vaptcha-init-loading {
display: table-cell;
vertical-align: middle;
text-align: center
}

.vaptcha-init-loading>a {
display: inline-block;
width: 18px;
height: 18px;
}

.vaptcha-init-loading>a img {
vertical-align: middle
}

.vaptcha-init-loading .vaptcha-text {
font-family: sans-serif;
font-size: 12px;
color: #CCCCCC;
vertical-align: middle
}
</style>
Partager