微信小程序-拼图动态验证


在这里插入图片描述
在这里插入图片描述

一、创建自定义组件verification-puzzle

verification-puzzle.js

var ctxShadow;
var ctxPuzzle;
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    width: {
      type: String,
      value: "500rpx"
    },
    height: {
      type: String,
      value: "80rpx"
    },
  },

  /**
   * 组件的初始数据
   */
  data: {
    oriSrc:'https://ns-strategy.cdn.bcebos.com/ns-strategy/upload/fc_big_pic/part-00798-3706.jpg',
    imgPuzzle: '',
    imgShadow: '',
    translateX: 0,
    oriX:0,
    x: 0,
    oldx: 0,
    isOk: false,
    size: {},
    width:"500rpx",
    height:"80rpx"
  },
  ready() {
    this.setData({
      width:this.properties.width,
      height:this.properties.height
    })
    this.drawPic(100, 70, 5)
    let getSize = (selector) => {
      return new Promise((resolve, reject) => {
        let view = wx.createSelectorQuery().in(this).select(selector);
        view.fields({
          size: true,
        }, (res) => {
          resolve(res.width);
        }).exec();
      });
    }
    getSize("#pathway").then((res1) => {
      this.data.size.pathway = res1;
      getSize("#track").then((res2) => {
        this.data.size.track = res2;
      });
    })
  },
  /**
   * 组件的方法列表
   */
  methods: {
    drawPic(x, y, r) {
      var that = this
      that.setData({
        translateX: -x,
        oriX:-x
      })
      ctxPuzzle = wx.createCanvasContext('canvasPuzzle',this)
      ctxShadow = wx.createCanvasContext('canvasShadow',this)
      this.clip(ctxPuzzle, x, y, r)
      wx.getImageInfo({
        src: that.data.oriSrc,
        success: function (res) {
          ctxPuzzle.drawImage(res.path, 0, 0, 250, 150);
          ctxPuzzle.restore();
          ctxPuzzle.draw(false, setTimeout(() => {
            wx.canvasToTempFilePath({
              canvasId: 'canvasPuzzle',
              success: function (e) {
                console.log("!!!!", e)
                that.setData({
                  imgPuzzle: e.tempFilePath
                })
              },
              fail: function (e) {
                console.log("AAAA", e)
              }
            }, that)
          }, 100))
        }
      })
      this.clip(ctxShadow, x, y, r)
      ctxShadow.setFillStyle('black')
      ctxShadow.setGlobalAlpha(0.5)
      ctxShadow.fillRect(0, 0, 250, 150)
      ctxShadow.draw(false, setTimeout(() => {
        wx.canvasToTempFilePath({
          canvasId: 'canvasShadow',
          success: function (e) {
            console.log("$$$$",e)
            that.setData({
              imgShadow: e.tempFilePath
            })
          }
        }, this)
      }, 100))
      
    },
    clip(ctx, x, y, r) {
      ctx.save();
      //开始一个新的绘制路径
      ctx.beginPath();
      //设置路径起点坐标
      ctx.moveTo(x, y);
      ctx.arcTo(x, y - r, x + r, y - r, r);
      ctx.lineTo(x + 2 * r, y - r);
      ctx.arcTo(x + 2 * r, y - 2 * r, x + 3 * r, y - 2 * r, r);
      ctx.arcTo(x + 4 * r, y - 2 * r, x + 4 * r, y - r, r);
      ctx.lineTo(x + 5 * r, y - r);
      ctx.arcTo(x + 6 * r, y - r, x + 6 * r, y, r);
      ctx.lineTo(x + 6 * r, y + r);
      ctx.arcTo(x + 7 * r, y + r, x + 7 * r, y + 2 * r, r);
      ctx.arcTo(x + 7 * r, y + 3 * r, x + 6 * r, y + 3 * r, r);
      ctx.lineTo(x + 6 * r, y + 4 * r);
      ctx.arcTo(x + 6 * r, y + 5 * r, x + 5 * r, y + 5 * r, r);
      ctx.lineTo(x + 4 * r, y + 5 * r);
      ctx.arcTo(x + 4 * r, y + 4 * r, x + 3 * r, y + 4 * r, r);
      ctx.arcTo(x + 2 * r, y + 4 * r, x + 2 * r, y + 5 * r, r);
      ctx.lineTo(x + r, y + 5 * r);
      ctx.arcTo(x, y + 5 * r, x, y + 4 * r, r);
      ctx.lineTo(x, y + 3 * r);
      ctx.arcTo(x + r, y + 3 * r, x + r, y + 2 * r, r);
      ctx.arcTo(x + r, y + r, x, y + r, r);
      ctx.lineTo(x, y);
      //先关闭绘制路径。注意,此时将会使用直线连接当前端点和起始端点。
      ctx.closePath();
      ctx.clip();
      ctx.stroke(); //画线轮廓
    },
    onChange(e) {
      this.setData({
        oldx: e.detail.x,
        translateX:this.data.oriX+e.detail.x
      })
    },
    onEnd() {
      if (this.data.isOk) {
        return;
      }
      if (((this.data.oldx) > (-this.data.oriX-2))&&(this.data.oldx<(2-this.data.oriX))) {
        this.setData({
          isOk: true
        }, () => {
          this.triggerEvent('result');
        });
        console.log("isOk",this.data.isOk)
      } else {
        this.setData({
          x: 0,
          oldx: 0
        })
      }
    }
  }
})

verification-puzzle.json

{
  "component": true,
  "usingComponents": {}
}

verification-puzzle.wxml

<view class="verificationPuzzleContainer">
  <view class="view-z-container">
    <canvas class="canvas-shadow" style="width:250px;height:150px;" disable-scroll="true" bindtouchstart="uploadScaleStart" bindtouchmove="uploadScaleMove" bindtouchend="uploadScaleEnd" bindtap="mouseDown" canvas-id="canvasShadow">
    </canvas>
    <canvas class="canvas-puzzle" style="width:250px;height:150px;" disable-scroll="true" bindtouchstart="uploadScaleStart" bindtouchmove="uploadScaleMove" bindtouchend="uploadScaleEnd" bindtap="mouseDown" canvas-id="canvasPuzzle">
    </canvas>
    <cover-image style="width:250px;height:150px;z-index:53;position: absolute;" src="{{oriSrc}}"></cover-image>
    <cover-image style="width:250px;height:150px;z-index:53;position: absolute;" src="{{imgShadow}}"></cover-image>
    <cover-image style="width:250px;height:150px;z-index:53;position: absolute;transform:translateX({{translateX}}px);" src="{{imgPuzzle}}"></cover-image>
  </view>
  <view wx:if="{{!isOk}}" class='pathway' style="width:250px;height:40px;margin-top:10rpx" bindtouchend='onEnd' id='pathway'>
    <view class="tips">
      <text wx:if="{{isOk}}" style="color: #FFFFFF;">验证通过</text>
      <text wx:else>拖动滑块拼图验证</text>
    </view>
    <view class="track" style="transform:translateX({{oldx}}px)"></view>
    <movable-area>
      <movable-view x="{{x}}" direction="horizontal" bindchange="onChange" class='{{isOk ? "active":""}}' id="track">
      </movable-view>
    </movable-area>
    <view class="disabled" wx:if="{{isOk}}"></view>
  </view>
  <view wx:if="{{isOk}}" style="width:250px;height:40px;margin-top:10rpx;background-color:#7ac23c;color:#FFFFFF;display: flex;flex-direction: column;justify-content: center;align-items: center;font-size: 32rpx;">拼图验证成功
  </view>
</view>

verification-puzzle.wxss

/* components/MoveVerify.wxss */
.verificationPuzzleContainer{
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.view-z-container{
  width: 500rpx;
  height: 300rpx;
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}
.canvas-shadow{
  z-index: 51;
  position: absolute;
}
.canvas-puzzle{
  z-index: 52;
  position: absolute;
}
.pathway {
  height: 80rpx;
  width: 100%;
  background-color: #7ac23c;
  position: relative;
  overflow: hidden;
}
 
.pathway .tips {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  line-height: 80rpx;
  text-align: center;
  color: #666;
  font-size: 32rpx;
  z-index: 3;
  display: flex;
  justify-content: center;
  align-items: center
}
 
.pathway .track {
  position: absolute;
  top: 0;
  left: 0;
  background-color: #eee;
  width: 100%;
  height: 100%;
  padding-left: 0;
  box-sizing: content-box;
  transform: translateX(0);
}
 
.pathway movable-area {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background: none;
  z-index: 5;
}
 
.pathway movable-view {
  height: 100%;
  width: 100rpx;
  box-sizing: border-box;
  background-color: #fff;
  border: #ddd solid 1px;
  background-position: center;
  background-repeat: no-repeat;
  background-size: auto 32rpx;
  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5YmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFegBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlhBXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwAAN9mIrUReCXgAAAABJRU5ErkJggg==");
}
 
.pathway movable-view.active {
  border: #7ac23c solid 1px;
  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDlBRDI3NjVGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDlBRDI3NjRGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWEzMWNhMC1hYmViLTQxNWEtYTEwZS04Y2U5NzRlN2Q4YTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k+sHwwAAASZJREFUeNpi/P//PwMyKD8uZw+kUoDYEYgloMIvgHg/EM/ptHx0EFk9I8wAoEZ+IDUPiIMY8IN1QJwENOgj3ACo5gNAbMBAHLgAxA4gQ5igAnNJ0MwAVTsX7IKyY7L2UNuJAf+AmAmJ78AEDTBiwGYg5gbifCSxFCZoaBMCy4A4GOjnH0D6DpK4IxNSVIHAfSDOAeLraJrjgJp/AwPbHMhejiQnwYRmUzNQ4VQgDQqXK0ia/0I17wJiPmQNTNBEAgMlQIWiQA2vgWw7QppBekGxsAjIiEUSBNnsBDWEAY9mEFgMMgBk00E0iZtA7AHEctDQ58MRuA6wlLgGFMoMpIG1QFeGwAIxGZo8GUhIysmwQGSAZgwHaEZhICIzOaBkJkqyM0CAAQDGx279Jf50AAAAAABJRU5ErkJggg==");
}
 
.pathway .disabled {
  position: absolute;
  z-index: 10;
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
}

二、在index页面使用

index.wxml

<verification-puzzle bind:result="verificationResult"></verification-puzzle>

index.js

// pages/test/test/test.js
Page({

  /**
   * 页面的初始数据
   */
  data: {},
  verificationResult() {
    console.log("验证通过");
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // this.randomVerification()
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

index.json

{
  "usingComponents": {
  	"verification-puzzle": "/components/verification-puzzle/verification-puzzle",
	}
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值