vue 拖拽图片验证
手机端效果 做了两套事件,没有放到一块做兼容,
拖拽认证
- 踩到的坑, 范围没有判断好会发生快速滑动卡顿,
if (moveX < 0) {
moveX = 0;
}
if (moveX + this.$refs.block.offsetWidth >= this.$refs.blockimg.offsetWidth) {
moveX =this.$refs.blockimg.offsetWidth - this.$refs.block.offsetWidth; // this.$refs.blockimg.offsetWidth 滑动范围 - this.$refs.block.offsetWidth 滑块大小
}
做了两套事件,没有放到一块做兼容, 有空做兼容
@mousedown=“sliderDown”
@touchstart=“touchStartEvent”
@touchmove=“touchMoveEvent”
@touchend=“touTouchend”
// 在另一个组件引用
<getcode ref="skuCard" @success="onSuccess"></getcode>
// 点击打开弹窗
obtainValidateFn(yzmCode) { // 调取弹窗组件
// 未输入手机号不能调取组件
this.$refs.skuCard.openCard();
},
**页面**
<template>
<div class="getCode">
<van-popup v-model="show" :overlay="false" close-icon="close" position="bottom" >
<div class="background">
<div class="top">
<div class="validation">请完成安全验证</div>
<van-icon class="vant-icon-cross" @click="cancel" name="cross" />
</div>
<div class="image">
<img class="img" ref="blockimg" :src="captcha.img" alt />
<van-icon class="vantt-icon-replay" @click="refresh" name="replay" />
<!-- @touchend="touTouchend" -->
<img
ref="block"
@mousedown="sliderDown"
@touchstart="touchStartEvent"
@touchmove="touchMoveEvent"
@touchend="touTouchend"
:style="{top:captcha.verify_block_y+'px',left:sliderLeft}"
class="slide-block-img"
:src="captcha.slide_block_img"
alt
/>
</div>
<div class="loading" v-if="loading">
<van-loading class="vant-loading" color="#1989fa" />
</div>
<div class="placeholder">{{resultText}}</div>
<div class="slide-verify-slider-mask" :style="{width: sliderMaskWidth}">
<!-- slider -->
<div
class="slide-verify-slider-mask-item"
:style="{left: sliderLeft ,}"
@mousedown="sliderDown"
@touchstart="touchStartEvent"
@touchmove="touchMoveEvent"
@touchend="touTouchend"
>
<van-icon class="vant-icon-arrow" name="arrow" />
</div>
</div>
</div>
</van-popup>
</div>
</template>
**script 代码块**
<script>
import { getcode, checkcode } from "../../server/api/getcode";
import { Toast } from "vant"; // 提示
export default {
props: {},
data() {
return {
placeholder:'向右滑动滑块',
show: false,
sliderLeft: 0, // 滑块的Left
sliderMaskWidth: 0, // 滑块 阴影的宽
captcha: {},
token: "",
motion_locus: [],
trail: [],
isMouseDown: false,
loading: false, // 控制 loading 显示隐藏
};
},
computed: {
resultText() {
let text = this.placeholder;
if (this.loading) {
text = '加载中';
}
return text;
},
},
created() {
},
watch: {},
methods: {
// 获取滑块信息
getSliderCode() {
this.loading = true;
if (document.body.clientWidth >= 1000) { // 判断页面的宽 分辨是移动端 还是H5端
getcode(this.$axios, {
width: 1433,
height: 665,
}).then((res) => {
if (res.code == 200) {
this.loading = false;
this.token = res.response.token;
this.captcha = res.response.captcha;
}
});
} else {
getcode(this.$axios, {
width: 280,
height: 130,
}).then((res) => {
if (res.code == 200) {
this.loading = false;
this.token = res.response.token;
this.captcha = res.response.captcha;
}
});
}
},
// 手指触摸屏幕
touchStartEvent(e) {
var slider = document.querySelector('.slide-verify-slider-mask-item')
var sliderMaskWidth = document.querySelector('.slide-verify-slider-mask')
slider.style.transition = "";
sliderMaskWidth.style.transition = ''
this.originX = e.changedTouches[0].pageX;
this.originY = e.changedTouches[0].pageY;
this.isMouseDown = true;
console.log(111)
},
// 手指移动
touchMoveEvent(e) {
if (!this.isMouseDown) return false;
let moveX = e.changedTouches[0].pageX - this.originX;
let moveY = e.changedTouches[0].pageY - this.originY;
if (moveX < 0) {
moveX = 0;
}
if (moveX + this.$refs.block.offsetWidth >= this.$refs.blockimg.offsetWidth) {
moveX =this.$refs.blockimg.offsetWidth - this.$refs.block.offsetWidth;
}
this.sliderLeft = moveX + "px";
this.sliderMaskWidth = moveX + "px";
// this.trail.push(moveY);
// this.positionx =e.clientX - this.originX + this.$refs.block.offsetLeft - 8;
this.positionx = Math.trunc(e.changedTouches[0].pageX - this.originX); // 取整
this.positiony = this.captcha.verify_block_y;
// console.log(this.positionx);
// console.log(this.positiony);
this.motion_locus.push({
block_position: {
x: this.positionx,
y: this.positiony,
},
time_stamp: (this.now = Date.parse(new Date())),
});
},
// 手指离开
touTouchend(e) {
var sliderLeft = document.querySelector('.slide-verify-slider-mask-item') // 获取dom元素
var sliderMaskWidth = document.querySelector('.slide-verify-slider-mask')
sliderLeft.style.transition = "left 0.4s ease-out 0s"; // 给dom元素添加动画
sliderMaskWidth.style.transition = 'width 0.4s ease-out 0s'
this.left_topy = this.positiony;
this.left_topx = this.positionx;
// console.log("this.left_topy", this.left_topy);
// console.log("this.left_topx", this.left_topx);
this.right_topx = this.positionx + this.$refs.block.offsetWidth;
this.right_topy = this.positiony;
// console.log(this.$refs.blockimg.offsetWidth);
// console.log(this.right_topx);
// console.log(this.right_topy);
this.left_bottomy = this.captcha.verify_block_y + this.$refs.block.offsetWidth;
this.left_bottomx = this.positionx;
// console.log(this.$refs.blockimg.offsetHeight);
// console.log(this.left_bottomy)
// console.log(this.left_bottomx)
this.right_bottomx = this.positionx + this.$refs.block.offsetWidth;
this.right_bottomy = this.captcha.verify_block_y + this.$refs.block.offsetWidth;
// console.log(this.right_bottomx);
// console.log(this.right_bottomy);
this.isMouseDown = false;
this.setCheckcode();
},
// 鼠标按下事件
sliderDown(e) {
var slider = document.querySelector('.slide-verify-slider-mask-item')
var sliderMaskWidth = document.querySelector('.slide-verify-slider-mask')
slider.style.transition = "";
sliderMaskWidth.style.transition = ''
this.originX = e.clientX;
this.originY = e.clientY;
this.isMouseDown = true;
// console.log(this.clientX)
// 鼠标移动事件
document.onmousemove = (e) => {
if (!this.isMouseDown) return false;
if (!this.isMouseDown) return false;
const moveX = e.clientX - this.originX;
const moveY = e.clientY - this.originY;
if (moveX < 0) {
moveX = 0;
}
if (moveX + this.$refs.block.offsetWidth >= this.$refs.blockimg.offsetWidth) {
moveX =this.$refs.blockimg.offsetWidth - this.$refs.block.offsetWidth;
}
this.sliderLeft = moveX + "px";
this.sliderMaskWidth = moveX + "px";
this.positionx = Math.trunc(e.clientX - this.originX);
this.positiony = this.captcha.verify_block_y;
e.preventDefault()
// console.log(this.positionx);
// console.log(this.positiony);
this.motion_locus.push({
block_position: {
x: this.positionx,
y: this.positiony,
},
time_stamp: (this.now = Date.parse(new Date())),
});
},
// 鼠标释放事件
document.onmouseup = (e) => {
this.isMouseDown = false;
var sliderLeft = document.querySelector('.slide-verify-slider-mask-item') // 获取dom元素
var sliderMaskWidth = document.querySelector('.slide-verify-slider-mask')
sliderLeft.style.transition = "left 0.4s ease-out 0s"; // 给dom元素添加动画
sliderMaskWidth.style.transition = 'width 0.4s ease-out 0s'
this.left_topy = this.positiony;
this.left_topx = this.positionx;
this.right_topx = this.positionx + this.$refs.block.offsetWidth;
this.right_topy = this.positiony;
this.left_bottomy = this.captcha.verify_block_y + this.$refs.block.offsetWidth;
this.left_bottomx = this.positionx;
this.right_bottomx = this.positionx + this.$refs.block.offsetWidth;
this.right_bottomy =this.captcha.verify_block_y + this.$refs.block.offsetWidth;
this.setCheckcode();
};
},
// 打开弹窗
openCard(type) {
this.show = true;
// 获取图片数据
this.getSliderCode();
},
// 刷新
refresh() {
this.getSliderCode();
this.motion_locus = []; // 刷新后清空验证信息
this.sliderLeft = 0;
this.sliderMaskWidth = 0;
},
// 取消
cancel() {
this.sliderLeft = 0;
this.sliderMaskWidth = 0;
this.show = false;
},
// 提交滑块信息
setCheckcode() {
checkcode(this.$axios, {
token: this.token,
motion_locus: this.motion_locus,
block_info: {
left_top: {
x: this.left_topx,
y: this.left_topy,
},
right_top: {
x: this.right_topx,
y: this.right_topy,
},
left_bottom: {
x: this.left_bottomx,
y: this.left_bottomy,
},
right_bottom: {
x: this.right_bottomx,
y: this.right_bottomy,
},
},
}).then((res) => {
if (res.code == 200) {
this.$emit("success", res.response.result);
this.result = res.response.result
// console.log(this.checkcodes);
if (res.response.result == true) {
Toast(res.response.msg);
(this.motion_locus = []), // 验证成功后清空提交push信息,会影响下次提交
setTimeout(() => {
this.cancel();
}, 500);
} else {
Toast("验证失败,请重新验证...");
this.refresh();
}
}
});
},
},
components: {},
};
</script>
**## scss代码**
.getCode {
.background {
width: 296px;
height: 231px;
margin: 0 auto;
// background: #fff;
.top {
display: flex;
.validation {
font-size: 18px;
padding: 10px 0 0 20px;
}
.vant-icon-cross {
margin: 10px 0 0 120px;
font-size: 15px;
}
}
.image {
width: 280px;
height: 130px;
margin: 10px auto;
.img {
width: 280px;
height: 130px;
position: absolute;
}
.slide-block-img {
position: relative;
// width: 50px;
// height: 50px;
z-index: 99;
}
.vantt-icon-replay {
position: absolute;
z-index: 99;
padding-left: 255px;
color: #fff;
font-size: 18px;
}
}
.loading {
position: absolute;
width: 281px;
height: 131px;
z-index: 99;
top: 40px;
margin-left: 7px;
background: #e5e5e5;
.vant-loading {
margin: 50px auto;
}
}
.placeholder{
border: 1px solid #e5e5e5;
// height: 100%;
width: 280px;
text-align: center;
line-height: 30px;
font-size: 14px;
margin: 19px 0 0 7px;
color: #333;
box-sizing: border-box;
border-radius: 2px;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none
}
.slide-verify-slider-mask {
position: absolute;
margin-left: 8px;
top: 190px;
height: 30px;
background: #d1e9fe;
opacity: .9;
}
.slide-verify-slider-mask-item {
position: absolute;
top: 0;
left: 0;
width: 50px;
height: 30px;
background: rgb(14, 77, 165);
text-align: center;
}
.vant-icon-arrow {
color: #fff;
line-height: 30px;
font-size: 14px;
}
}
}
> 两个事件放到一块做兼容PC 和 安卓
methods: {
bindEvents() {
this.body.addEventListener("mousedown", handleDragStart);
this.body.addEventListener("touchstart", handleDragStart);
document.addEventListener("mousemove", this.handleDragMove);
document.addEventListener("touchmove", this.handleDragMove);
document.addEventListener("mouseup", this.handleDragEnd);
document.addEventListener("touchend", this.handleDragEnd);
},
// 获取滑块信息
getSliderCode() {
this.loading = true;
if (document.body.clientWidth >= 1000) {
// 判断页面的宽 分辨是移动端 还是H5端
getcode(this.$axios, {
width: 906,
height: 420,
}).then((res) => {
if (res.code == 200) {
this.loading = false;
this.token = res.response.token;
this.captcha = res.response.captcha;
}
});
} else {
getcode(this.$axios, {
width: 280,
height: 130,
}).then((res) => {
if (res.code == 200) {
this.loading = false;
this.token = res.response.token;
this.captcha = res.response.captcha;
}
});
}
},
// 手指触摸屏幕
handleDragStart(e) {
let slider = document.querySelector(".slide-verify-slider-mask-item");
let sliderMaskWidth = document.querySelector(".slide-verify-slider-mask");
slider.style.transition = "";
sliderMaskWidth.style.transition = "";
this.originX = e.clientX || e.changedTouches[0].pageX;
this.originY = e.clientY || e.changedTouches[0].pageY;
this.isMouseDown = true;
},
// 手指移动
handleDragMove(e) {
if (!this.isMouseDown) return false;
let eventX = e.clientX || e.changedTouches[0].pageX;
let eventY = e.clientY || e.changedTouches[0].pageY;
let moveX = eventX - this.originX;
let moveY = eventY - this.originY;
if (moveX < 0) {
moveX = 0;
}
if (
moveX + this.$refs.block.offsetWidth >=
this.$refs.blockimg.offsetWidth
) {
moveX = this.$refs.blockimg.offsetWidth - this.$refs.block.offsetWidth;
}
this.sliderLeft = moveX + "px";
this.sliderMaskWidth = moveX + "px";
this.trail.push(moveY);
this.positionx = Math.trunc(eventX - this.originX); // 取整
this.positiony = this.captcha.verify_block_y;
this.motion_locus.push({
block_position: {
x: this.positionx,
y: this.positiony,
},
time_stamp: (this.now = Date.parse(new Date())),
});
},
// 手指离开
handleDragEnd(e) {
this.isMouseDown = false;
let slider = document.querySelector(".slide-verify-slider-mask-item"); // 获取dom元素
let sliderMaskWidth = document.querySelector(".slide-verify-slider-mask");
slider.style.transition = "left 0.4s ease-out 0s"; // 给dom元素添加动画
sliderMaskWidth.style.transition = "width 0.4s ease-out 0s";
this.left_topy = this.positiony;
this.left_topx = this.positionx;
this.right_topx = this.positionx + this.$refs.block.offsetWidth;
this.right_topy = this.positiony;
this.left_bottomy =
this.captcha.verify_block_y + this.$refs.block.offsetWidth;
this.left_bottomx = this.positionx;
this.right_bottomx = this.positionx + this.$refs.block.offsetWidth;
this.right_bottomy =
this.captcha.verify_block_y + this.$refs.block.offsetWidth;
this.setCheckcode();
},
// 打开弹窗
openCard(type) {
this.show = true;
// 获取图片数据
this.getSliderCode();
},
// 刷新
refresh() {
this.getSliderCode();
this.motion_locus = []; // 刷新后清空验证信息
this.sliderLeft = 0;
this.sliderMaskWidth = 0;
},
// 取消
cancel() {
this.sliderLeft = 0;
this.sliderMaskWidth = 0;
this.show = false;
},
// 提交滑块信息
setCheckcode() {
checkcode(this.$axios, {
token: this.token,
motion_locus: this.motion_locus,
block_info: {
left_top: {
x: this.left_topx,
y: this.left_topy,
},
right_top: {
x: this.right_topx,
y: this.right_topy,
},
left_bottom: {
x: this.left_bottomx,
y: this.left_bottomy,
},
right_bottom: {
x: this.right_bottomx,
y: this.right_bottomy,
},
},
}).then((res) => {
if (res.code == 200) {
this.$emit("success", res.response.result);
this.result = res.response.result;
// console.log(this.checkcodes);
if (res.response.result == true) {
Toast(res.response.msg);
(this.motion_locus = []), // 验证成功后清空提交push信息,会影响下次提交
setTimeout(() => {
this.cancel();
}, 500);
} else {
Toast("验证失败,请重新验证...");
this.refresh();
}
}
});
},
},