先看效果
做的是粗糙版本,需要其他的效果,可以在原有基礎上進行修改
思路
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>
如果有什么錯誤的地方歡迎大家指正🤞🤞🤞