版权声明:来自MarieDreamer https://blog.csdn.net/qq_33514421/article/details/83052247
前言
看到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)
}
})