vue怎么实现手势密码
Vue 实现手势密码的方法
使用第三方库 vue-gesture-password
vue-gesture-password 是一个专门为 Vue 设计的轻量级手势密码组件,支持自定义样式和事件。
安装:
npm install vue-gesture-password --save
基本用法:
<template>
<GesturePassword
:width="300"
:height="300"
@complete="onComplete"
/>
</template>
<script>
import GesturePassword from 'vue-gesture-password'
export default {
components: { GesturePassword },
methods: {
onComplete(password) {
console.log('输入的密码:', password)
// 验证密码逻辑
}
}
}
</script>
自定义实现手势密码
如果需要完全自定义实现,可以通过监听触摸事件和绘制逻辑来完成。
HTML 结构:
<template>
<div class="gesture-container" ref="container">
<canvas ref="canvas" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd"></canvas>
</div>
</template>
核心逻辑:
<script>
export default {
data() {
return {
points: [], // 所有点
selectedPoints: [], // 选中的点
isDrawing: false,
ctx: null
}
},
mounted() {
this.initCanvas()
},
methods: {
initCanvas() {
const canvas = this.$refs.canvas
this.ctx = canvas.getContext('2d')
// 设置canvas尺寸
canvas.width = this.$refs.container.offsetWidth
canvas.height = this.$refs.container.offsetHeight
// 初始化点
this.initPoints()
},
initPoints() {
// 创建3x3的点阵
const radius = 10
const spacing = (this.$refs.canvas.width - radius * 6) / 2
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
this.points.push({
x: radius + j * (radius * 2 + spacing),
y: radius + i * (radius * 2 + spacing),
radius,
index: i * 3 + j
})
}
}
this.drawPoints()
},
drawPoints() {
this.ctx.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)
// 绘制所有点
this.points.forEach(point => {
this.ctx.beginPath()
this.ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2)
this.ctx.fillStyle = this.selectedPoints.includes(point) ? '#409EFF' : '#ddd'
this.ctx.fill()
})
// 绘制连线
if (this.selectedPoints.length > 1) {
this.ctx.beginPath()
this.ctx.moveTo(this.selectedPoints[0].x, this.selectedPoints[0].y)
for (let i = 1; i < this.selectedPoints.length; i++) {
this.ctx.lineTo(this.selectedPoints[i].x, this.selectedPoints[i].y)
}
this.ctx.strokeStyle = '#409EFF'
this.ctx.lineWidth = 3
this.ctx.stroke()
}
},
onTouchStart(e) {
this.isDrawing = true
this.checkPoint(e.touches[0].clientX, e.touches[0].clientY)
},
onTouchMove(e) {
if (!this.isDrawing) return
this.checkPoint(e.touches[0].clientX, e.touches[0].clientY)
},
onTouchEnd() {
this.isDrawing = false
const password = this.selectedPoints.map(p => p.index).join('')
this.$emit('complete', password)
// 重置
setTimeout(() => {
this.selectedPoints = []
this.drawPoints()
}, 500)
},
checkPoint(x, y) {
const rect = this.$refs.canvas.getBoundingClientRect()
const touchX = x - rect.left
const touchY = y - rect.top
for (const point of this.points) {
const distance = Math.sqrt(
Math.pow(touchX - point.x, 2) + Math.pow(touchY - point.y, 2)
)
if (distance <= point.radius && !this.selectedPoints.includes(point)) {
this.selectedPoints.push(point)
this.drawPoints()
break
}
}
}
}
}
</script>
样式优化
添加基础样式使组件更美观:
<style scoped>
.gesture-container {
width: 100%;
max-width: 300px;
margin: 0 auto;
background: #f5f5f5;
border-radius: 8px;
padding: 20px;
box-sizing: border-box;
}
canvas {
width: 100%;
height: 300px;
display: block;
background: #fff;
border-radius: 4px;
}
</style>
注意事项
- 移动端需要添加
touch-action: none样式防止页面滚动 - 密码验证逻辑应该在父组件中实现
- 可以通过 props 传入正确密码进行比对
- 考虑添加错误提示和重试功能







