vue 图片滑动验证
先看效果
做的是粗糙版本,需要其他的效果,可以在原有基础上进行修改
思路
1.上半部分红色的为背景canvas,绿色的为缺失部分canvas
2.这两个canvas要在同一位置,并且为同一张背景图,随机选择图片上的一块小方格,将红色canvas的该部分填充浅色,做出缺失一块的效果,绿色canvas除了选中的方格子留下,其他部分都删除
3.绿色canvas移到最左边
4.下半部分红色部分为滑块滑动部分,蓝色部分为小滑块
5.蓝色滑块滑动时,上面绿色的canvas也要跟着滑块滑动,绿色的canvas与红色canvas部分重合,则成功,不重合滑块与绿色canvas就会回到最左边
6.刷新就是将两个canvas中的图片换成其他图片,并且将滑块和绿色canvas移动到最左边
代码部分
<template> <div class="yazheng" ref="yanzheng">
<!-- 背景滑块 -->
<canvas ref="slideVerify" class="slide-img"></canvas>
<!-- 图片 -->
<div style="display:none">
<img ref="imgs" :src="imgList[imgIndex]"/>
</div>
<!-- 下面滑块部分 -->
<div class="slide-wrapper bg-start">
<div class="btn" ref="btn" @mousedown="mouseDown" @mouseup="mouseUp"></div>
<p class="text" ref="text">{{content}}</p>
<!-- 拖动的时候出现的绿色背景 -->
<div class="bg" ref="bg"></div>
</div>
<!-- 刷新按钮 -->
<p @click="reflesh">刷新</p>
</div>
</template>
绿色canvas部分我们选择生成canvas,然后再插入到红色canvas(ref=\'slideVerify\')的前面,如果绿色canvas是直接写上去的不是动态生成的会造成一些问题,下文我会说会有什么问题
先写滑块部分的代码
mouseDown(e) { //滑块按下去的时候,我们要设置isDown为true,为了确保是按下滑块滑动
this.isDown = true;
//点击滑块的位置,和滑块的左端相差的距离
this.btnX = e.clientX - this.$refs.btn.offsetLeft;
},
mouseMove(e) {
//滑块左端向右边移动的距离
let moveX = e.clientX - this.btnX;
//确认滑块是在按下时拖动
if (this.isDown) {
//滑块滑动的位置,不能超过最左端和最右端,就是不能让滑块滑出去
if (this.$refs.btn.offsetLeft <= 260 && this.$refs.btn.offsetLeft >= 0) {
//滑块移动
this.$refs.btn.style.left = `${moveX}px`;
//绿色canvas移动
this.blockCanvas.style.left = `${moveX - this.imgX}px`;
//绿色背景出现,呈现出拉动的效果
this.$refs.bg.style.width = `${moveX}px`;
}
}
},
mouseUp() {
//滑块最左边部分滑动的距离
let leftX = this.$refs.btn.offsetLeft;
//绿色canvas的位置和红色canvas缺失的重合允许左右2px的误差
if (this.imgX >= leftX - 2 && this.imgX <= leftX + 2) {
this.isDown = false;
}
if (this.isDown) {
//如果滑动成功,那么滑块和绿色canvas会回到最初位置
this.$refs.btn.style.left = 0;
this.blockCanvas.style.left = `-${this.imgX}px`;
this.$refs.bg.style.width = 0;
}
this.isDown = false;
}
注意点:
由于我们点击的时候和滑块的最左边有一定的差值,如果我们每次将滑块移动的位置,都是鼠标移动的距离,就会产生滑块多移动了差值的距离,就是会移动到,下图绿色的位置,并且会导致我们的鼠标一直作用不到滑块的身上
canvas部分
//画图imageCanvas() {
//我们要刷新的时候需要把之前生成的绿色的canvas删除,在重新创建新的canvas
this.blockCanvas ? this.blockCanvas.remove() : null
this.blockCanvas = this.createCanvas(300, 150)
this.$refs.yanzheng.insertBefore(this.blockCanvas,this.$refs.slideVerify)
let x = this.randomNumber(60, 200),
y = 40;
this.imgX = x;
console.log(\'xxxx\',x,y)
let c = this.$refs.slideVerify;
let bg = c.getContext("2d");
let img = this.$refs.imgs;
let bk = this.blockCanvas.getContext("2d");
//在两块画布上都放上相同的图片
img.onload = () => {
bg.drawImage(img, 0, 0);
bk.drawImage(img, 0, 0);
};
this.drawBlock(bg, x, y, "fill");
this.drawBlock(bk, x, y, "clip");
},
//画抠出来的方块
drawBlock(ctx, x, y, type) {
console.log(\'xxxxxxxxxxxxxxxxxxxxxxxxx\',x)
let w = 40;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + w, y);
ctx.lineTo(x + w, y + w);
ctx.lineTo(x, y + w);
ctx.lineTo(x, y);
ctx.lineWidth = 0;
ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
ctx.strokeStyle = "rgba(255, 255, 255, 0.5)";
ctx.stroke();
ctx[type]();
ctx.globalCompositeOperation = "destination-over";
this.blockCanvas.style.left = `-${x}px`;
// console.log(this.$refs.block.style.left)
},
//刷新
refresh(){
this.clean()
this.imgIndex = this.randomNumber(0,6)
this.$refs.btn.style.left = 0;
this.$refs.bg.style.width = 0;
this.isDown = false, //鼠标是否按下
this.btnX = 0, //鼠标点击的水平位置与滑块移动水平位置的差
this.imgX = 0
this.imageCanvas(\'restore\')
},
//清空canvas
clean(){
let cxt2=this.$refs.slideVerify.getContext("2d");
cxt2.clearRect(0,0,300,150);
},
//新建canvas
createCanvas (width, height) {
const canvas = document.createElement(\'canvas\')
canvas.width = width
canvas.height = height
canvas.style.position = \'absolute\'
// canvas.style.border = \'1px solid red\'
return canvas
}
注意:
所以初始的时候绿色canvas的位置,是要根据方块随机产生的位置所决定的
之前说过不能先把绿色的canvas在html结构中写出,原因如下:
clip()函数,会把不要的部分删除,就算清除画布后,刷新下次画图也只会在没删除的部分画,如下图,所以你需要在合适的时候保留没有剪切时候的画布,并在合适的时候恢复保留时候的画布
但是这个样子就会出现新的问题,会导致绿色画布中的小方格出现重影(我也不知道该怎么描述这个东西了,只能说是重影),还是图片展示下重影吧,这边偷懒了,点击图片就会刷新,没有找出合适的办法解决这个问题所以就用重新创建canvas的办法,实现了功能,如果哪位大佬有解决的办法可以留言告诉我
所有代码
SlideVerify.vue
<template> <div class="yazheng" ref="yanzheng">
<!-- 背景滑块 -->
<canvas ref="slideVerify" class="slide-img"></canvas>
<!-- 图片 -->
<div style="display:none">
<img ref="imgs" :src="imgList[imgIndex]"/>
</div>
<!-- 下面滑块部分 -->
<div class="slide-wrapper bg-start">
<div class="btn" ref="btn" @mousedown="mouseDown" @mouseup="mouseUp"></div>
<p class="text" ref="text">{{content}}</p>
<!-- 拖动的时候出现的绿色背景 -->
<div class="bg" ref="bg"></div>
</div>
<!-- 刷新按钮 -->
<p @click="refresh">刷新</p>
</div>
</template>
<script>
export default {
name: "SlideVerify",
data() {
return {
imgIndex:0,
blockCanvas:null,
imgList:[require(\'../assets/1.jpg\'),
require(\'../assets/2.jpg\'),
require(\'../assets/3.jpg\'),
require(\'../assets/4.jpeg\'),
require(\'../assets/5.jpg\'),
require(\'../assets/6.jpg\'),],
content: "滑动滑块",
isDown: false, //鼠标是否按下
btnX: 0, //鼠标点击的水平位置与滑块移动水平位置的差
imgX: 0 //图片的水平位置
};
},
methods: {
//生成随机数字
randomNumber(min, max) {
return Math.floor(Math.random() * (max - min) + min);
},
mouseDown(e) {
//滑块按下去的时候,我们要设置isDown为true,为了确保是按下滑块滑动
this.isDown = true;
//点击滑块的位置,和滑块的左端相差的距离
this.btnX = e.clientX - this.$refs.btn.offsetLeft;
},
mouseMove(e) {
//滑块左端向右边移动的距离
let moveX = e.clientX - this.btnX;
//确认滑块是在按下时拖动
if (this.isDown) {
console.log(\'hahahhahah\',this.blockCanvas.style.left)
//滑块滑动的位置,不能超过最左端和最右端,就是不能让滑块滑出去
if (this.$refs.btn.offsetLeft <= 259 && this.$refs.btn.offsetLeft >= 0) {
console.log(moveX);
//滑块移动
this.$refs.btn.style.left = `${moveX}px`;
//绿色canvas移动
this.blockCanvas.style.left = `${moveX - this.imgX}px`;
//绿色背景出现,呈现出拉动的效果
this.$refs.bg.style.width = `${moveX}px`;
}
}
},
mouseUp() {
//滑块最左边部分滑动的距离
let leftX = this.$refs.btn.offsetLeft;
console.log(this.imgX,leftX)
//绿色canvas的位置和红色canvas缺失的重合允许左右2px的误差
if (this.imgX >= leftX - 2 && this.imgX <= leftX + 2) {
this.isDown = false;
}
if (this.isDown) {
//如果滑动成功,那么滑块和绿色canvas会回到最初位置
this.$refs.btn.style.left = 0;
this.blockCanvas.style.left = `-${this.imgX}px`;
this.$refs.bg.style.width = 0;
}
this.isDown = false;
},
//画图
imageCanvas() {
//我们要刷新的时候需要把之前生成的绿色的canvas删除,在重新创建新的canvas
this.blockCanvas ? this.blockCanvas.remove() : null
this.blockCanvas = this.createCanvas(300, 150)
this.$refs.yanzheng.insertBefore(this.blockCanvas,this.$refs.slideVerify)
let x = this.randomNumber(60, 200),
y = 40;
this.imgX = x;
console.log(\'xxxx\',x,y)
let c = this.$refs.slideVerify;
let bg = c.getContext("2d");
let img = this.$refs.imgs;
let bk = this.blockCanvas.getContext("2d");
//在两块画布上都放上相同的图片
img.onload = () => {
bg.drawImage(img, 0, 0);
bk.drawImage(img, 0, 0);
};
this.drawBlock(bg, x, y, "fill");
this.drawBlock(bk, x, y, "clip");
},
//画抠出来的方块
drawBlock(ctx, x, y, type) {
console.log(\'xxxxxxxxxxxxxxxxxxxxxxxxx\',x)
let w = 40;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + w, y);
ctx.lineTo(x + w, y + w);
ctx.lineTo(x, y + w);
ctx.lineTo(x, y);
ctx.lineWidth = 0;
ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
ctx.strokeStyle = "rgba(255, 255, 255, 0.5)";
ctx.stroke();
ctx[type]();
ctx.globalCompositeOperation = "destination-over";
this.blockCanvas.style.left = `-${x}px`;
// console.log(this.$refs.block.style.left)
},
//刷新
refresh(){
this.clean()
this.imgIndex = this.randomNumber(0,6)
this.$refs.btn.style.left = 0;
this.$refs.bg.style.width = 0;
this.isDown = false, //鼠标是否按下
this.btnX = 0, //鼠标点击的水平位置与滑块移动水平位置的差
this.imgX = 0
this.imageCanvas(\'restore\')
},
//清空canvas
clean(){
// let cxt1=this.blockCanvas.getContext("2d");
let cxt2=this.$refs.slideVerify.getContext("2d");
// cxt1.clearRect(0,0,300,150);
cxt2.clearRect(0,0,300,150);
},
//新建canvas
createCanvas (width, height) {
const canvas = document.createElement(\'canvas\')
canvas.width = width
canvas.height = height
canvas.style.position = \'absolute\'
// canvas.style.border = \'1px solid red\'
return canvas
}
},
mounted() {
this.imgIndex = this.randomNumber(0,6)
//将移动事件绑定在document上,绑定在dom元素上会导致滑块滑的太快触发不到鼠标移动事件
document.addEventListener("mousemove", this.mouseMove);
this.imageCanvas();
}
};
</script>
<style scoped>
.yazheng {
position: relative;
width: 300px;
margin: 0 auto;
/* border: 1px solid red; */
}
.slide-wrapper {
position: relative;
width: 300px;
height: 40px;
}
.bg-start {
background: cadetblue;
}
.bg {
position: absolute;
height: 40px;
background: rgb(34, 218, 80);
}
.text {
position: absolute;
width: 100%;
height: 40px;
text-align: center;
line-height: 40px;
margin: 0;
/* z-index: 1; */
}
.text-success {
color: white;
z-index: 2;
}
.btn {
position: absolute;
width: 40px;
height: 50px;
top: -5px;
z-index: 1;
border-radius: 5px;
background: rgb(143, 145, 148);
}
</style>
如果有什么错误的地方欢迎大家指正
以上是 vue 图片滑动验证 的全部内容, 来源链接: utcz.com/z/378900.html