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



		
		
		

还没有评论,来说两句吧...