1. 程式人生 > >js 滑動驗證

js 滑動驗證

前言

看到B站的滑動驗證,便跟著做了一個。我檢查了b站的元素,發現它的背景圖片好像是切成了很多塊,可能是後臺處理的圖片放到前端。我這個案例是純html+css+js做的,可以在後臺取隨機數為滑動條驗證正確的x位置。但是這樣做可能安全性不高,以後再研究後臺處理圖片的方法。希望有大佬看到能夠提點。

效果

 思路

1、放置一張背景圖片,在圖中指定範圍內生成一個拼圖凹槽(圖片)

2、在大圖下方放置滑動條,滑動時生成同x位置的拼圖圖片,並且y位置與拼圖凹槽一直,x值隨滑動條繫結。

3、當拼圖圖片x位置與拼圖凹槽一致,並且滑動條鬆開,則成功,否則失敗,並還原滑動條,銷燬兩個拼圖圖片。

關於如何獲取到被“摳”出的那塊圖片區域,我其實是將圖片複製,只顯示那個位置的區域,並用css的clip-path屬性裁剪出拼圖的形狀。這個方法很笨,主要我現在對css遮罩不瞭解。如果有更好的方法會馬上優化的,歡迎指正!~

程式碼

wxml

<view class='info' style='display:{{info?"block":"none"}}'>
  {{info_text}}
</view>

<view class='bar1' 
style="height:{{bar_height+200}}rpx;width:{{bar_width+20}}rpx;border-radius:{{bar_height/2}}rpx;background-image:url(../../images/bg.png);background-size:100% 100%;">
<!-- 活動的拼圖 -->
  <view class='pintu1 {{show?"show":"hide"}}' style='margin-left:{{left}}rpx;width:{{ball_width+20}}rpx;height:{{ball_width+20}}rpx;margin-top:{{top}}rpx;' bindtouchstart='touchS' bindtouchmove='touchM' bindtouchend='touchE'>
  <view style='width:{{ball_width+20}}rpx;height:{{ball_width+20}}rpx;background-image:url(../../images/bg.png);background-size:{{bar_width+20}}rpx {{bar_height+200}}rpx;position:absolute;z-index:2;background-repeat:no-repeat;background-position-x:{{-left_random}}rpx;background-position-y:{{-top}}rpx;clip-path: polygon(6% 22%, 31% 22%, 31% 6%, 53% 6%, 53% 22%, 77% 22%, 77% 47%, 93% 47%, 93% 68%, 77% 68%, 77% 93%, 53% 93%,53% 75%,31% 75%,31% 93%,6% 93%,6% 68%,24% 68%,24% 47%,6% 47%)'>
  </view>
  <view style='width:{{ball_width+20}}rpx;height:{{ball_width+20}}rpx;position:absolute;background:gray;clip-path: polygon(5% 21%, 30% 21%, 30% 5%, 54% 5%, 54% 21%, 78% 21%, 78% 46%, 93% 46%, 93% 69%, 78% 69%, 78% 94%, 52% 94%,52% 75%,31% 75%,31% 93%,6% 93%,6% 68%,24% 68%,24% 47%,6% 47%)'>
  </view>
</view>
  <!-- 目標拼圖 -->
  <image src="../../images/pintu2_final.png" class='pintu2 {{show?"show":"hide"}}'
  style='margin-left:{{left_random}}rpx;width:{{ball_width+20}}rpx;height:{{ball_width+20}}rpx;margin-top:{{top}}rpx;'></image>
</view>

<!-- 控制條 -->
<view class='bar' style="height:{{bar_height}}rpx;width:{{bar_width}}rpx;border-radius:{{bar_height}}rpx;">
  <view class='ball' id="ball" style='margin-left:{{left}}rpx;width:{{ball_width}}rpx;' bindtouchstart='touchS' bindtouchmove='touchM' bindtouchend='touchE'></view>
</view>

wxss

page{
  background: #eee
}
.bar1{
  background: #fff;
  margin: 50rpx auto;
  padding: 10rpx;
  display: flex;
  position: relative;
  z-index: 1;
}
.bar{
  background: #fff;
  margin: 50rpx auto;
  padding: 10rpx;
  display: flex;
  align-items: center;
  position: relative;
  z-index: 1;
}
.road{
  background: red;
  width:100%;
  height:100%;
}
.ball{
  border-radius: 100%;
  background-color: #aaa;
  height: 100%;
}
.pintu1{
  position: absolute;
  z-index: 3;
}
.pintu2{
  position: absolute;
  z-index: 2;
}
.show{
  display: block;
}
.hide{
  display: none;
}
.info{
  background: black;
  left: 50%;
  transform:translate(-50%, 0);
  opacity: 0.6;
  width: 300rpx;
  height: 200rpx;
  position: absolute;
  z-index: 3;
  top:85rpx;
  border-radius: 10rpx;
  color: white;
  line-height: 200rpx;
  text-align: center;
}

js

Page({

  data: {
    left:0,
    show:0
  },

  onLoad: function (options) {
    
  },
  onReady:function(e){
    let self = this;
    this.setData({
      bar_width : 400,
      bar_height : 50
    })
    //獲取小球高度
    var query = wx.createSelectorQuery();
    query.select('#ball').boundingClientRect()
    query.exec(function (res) {
      var h = res[0].height;
      self.setData({
        ball_width: h*2
      })
    })

    const ctx = wx.createCanvasContext('myCanvas')
    ctx.setFillStyle('red')
    ctx.fillRect(10, 10, 150, 75)
    ctx.draw()
  },
  touchS:function(e){
    this.data.start = e.touches[0].pageX;
    this.data.start_left = this.data.left;
    this.setData({
      show:1,
      top: Math.floor(Math.random() * (this.data.bar_height + 180 - this.data.ball_width)),
      left_random: Math.floor(Math.random() * (this.data.bar_width-this.data.ball_width)/2+150)
    })

  },
  touchM:function(e){
    this.data.end = e.touches[0].pageX;
    this.data.move = this.data.end - this.data.start;
    this.data.end_left = this.data.start_left + this.data.move * 2;
    if (this.data.end_left < 0){
      this.setData({
        left: 0
      })
    } else if (this.data.end_left > this.data.bar_width - this.data.ball_width){
      this.setData({
        left: this.data.bar_width - this.data.ball_width
      })
    }else{
      this.setData({
        left: this.data.end_left
      })
    }
  },
  touchE:function(e){
    var info = '';
    let that = this;
    if (this.data.left > this.data.left_random - 10 && this.data.left < this.data.left_random + 10){
      info='success'
    }else{
      info = 'fail'
    }
    this.setData({
      info: 1,
      info_text: info
    })
    setTimeout(function () {
      that.setData({
        info: 0,
        show:0,
        left:0
      })
    }, 1000)
  }

})