vue 图片滑动验证


先看效果

huadongyanzheng.gif

做的是粗糙版本,需要其他的效果,可以在原有基础上进行修改

思路

image.png

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;
}

注意点:
image.png

由于我们点击的时候和滑块的最左边有一定的差值,如果我们每次将滑块移动的位置,都是鼠标移动的距离,就会产生滑块多移动了差值的距离,就是会移动到,下图绿色的位置,并且会导致我们的鼠标一直作用不到滑块的身上

image.png

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
}

注意:
image.png
所以初始的时候绿色canvas的位置,是要根据方块随机产生的位置所决定的

之前说过不能先把绿色的canvas在html结构中写出,原因如下:

  1. clip()函数,会把不要的部分删除,就算清除画布后,刷新下次画图也只会在没删除的部分画,如下图,所以你需要在合适的时候保留没有剪切时候的画布,并在合适的时候恢复保留时候的画布
    image.png

  2. 但是这个样子就会出现新的问题,会导致绿色画布中的小方格出现重影(我也不知道该怎么描述这个东西了,只能说是重影),还是图片展示下重影吧,这边偷懒了,点击图片就会刷新,没有找出合适的办法解决这个问题所以就用重新创建canvas的办法,实现了功能,如果哪位大佬有解决的办法可以留言告诉我
    chongyin.gif

所有代码

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>

如果有什么错误的地方欢迎大家指正🤞🤞🤞


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM