https://blog.51cto.com/u_15930000/7324703
父组件:
<button @click="handleOpen">打开滑块弹窗</button>
<sliderVerify ref="sliderVerifyRef" @verifyCode="getVefCodeTrue"></sliderVerify>
import sliderVerify from './sliderVerify.vue'
handleLogin(){
this.$refs.sliderVerifyRef.getSlideBlockApi()
}
// 滑块验证结果回调函数
getVefCodeTrue(captcha){
console.log(captcha)
}
sliderVerify.vue文件
<template>
<view class="frame--dialog">
<view class="frameBg" v-show="showModal" style="z-index:10"></view>
<view class="framework" v-if="isVefCode">
<view class="boxTopTitle">
<text>请拖动滑块完成拼图</text>
<uni-icons type="closeempty" size="20" @click="handleCloseRef"></uni-icons>
</view>
<view class="boxImg">
<view class="cutImgSet" :class="isAnimation?'animation':''" :style="{top:CutImgY+'px', left: blockLeft + 'px'}">
<image :src="CutImg" style="cursor:pointer; z-index: 10;"
:style="{width:cutWidth+'px',height:cutHeight+'px'}"></image>
</view>
<image :src="BGImg" style="border-radius:8px; width: 320px;height: 155px;"></image>
<view class="reset" @click="getSlideBlockApi">
<uni-icons type="refreshempty" size="30"></uni-icons>
</view>
</view>
<view class="checkBox">
<view class="checkBar">
<view class="slide">
<view :class="'moveBac '+(isAnimation?' animation':'')" :style="'width:'+blockLeft+'px;'"></view>
<view class="successBlock" :class="'swiperBlock '+(isAnimation?' animation':'') "
:style="'left:'+blockLeft+'px'" ref="sliderBtn" @touchstart="handleTouchstart"
@touchmove.stop.prevent="handleTouchmove" @touchend="handleTouchend">
<uni-icons type="arrow-right" size="30" color="#ffffff"></uni-icons>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
getSlider
} from "./api.js";
export default {
props: {
theme: {
type: String,
},
barWidth: {
type: Number,
default: 300
}
},
data() {
return {
BGImg: '',
CutImg: '',
CutImgY: '',
isVefCode: false,
showModal: false,
startInfo: {},
blockLeft: 0, //随机拼图的最终X轴距离
isAnimation: false,
cutWidth: 65,
cutHeight: 55,
nonceStr: ''
}
},
computed: {
trueMoveableW: function() {
return this.barWidth - 40
}
},
methods: {
//初始化
async getSlideBlockApi() {
let res = await getSlider({});
if (res?.code == 200) {
// nonceStr.value = res.data.nonceStr;
// return res.data;
this.BGImg = res.data.canvasSrc; //大图
this.CutImg = res.data.blockSrc; //拼图
this.CutImgY = res.data.blockY; //接口位置
this.cutWidth = res.data.blockWidth;//拼图宽度
this.cutHeight = res.data.blockHeight;//拼图高度
this.handleOpenRef()
}
},
//手指按下
handleTouchstart({
changedTouches
}) {
this.isAnimation = false
this.startInfo = changedTouches[0]
},
// 手指移动
handleTouchmove({
changedTouches
}) {
let blockLeft = changedTouches[0].clientX - this.startInfo.clientX
let blockLeftRpx = blockLeft;
if (blockLeftRpx < 0) {
this.blockLeft = 0
} else {
this.blockLeft = blockLeftRpx <= this.trueMoveableW ? blockLeftRpx : this.trueMoveableW
}
},
// 手指离开
handleTouchend(e) {
this.$emit('verifyCode', {
value: this.blockLeft
})
},
/* 鼠标滑块移动 */
moving(e) {
let self = this;
e = e || window.event;
let moveX = (e.pageX || e.targetTouches[0].pageX);
let d = moveX - self.moveStart;
let w = self.dataWidth;
let PL_Size = this.puzzleSize;
let padding = this.padding;
if (self.moveStart === "") {
return "";
}
if (d < 0 || d > w - padding - PL_Size) {
return "";
}
if (d <= 260) {
self.blockLeft = d
}
},
handleCloseRef() {
this.showModal = false;
this.isVefCode = false;
// 重置滑块位置
this.blockLeft = 0;
},
handleOpenRef(msg) {
this.showModal = true;
this.isVefCode = true;
},
}
}
</script>
<style lang="scss" scoped="scoped">
.framework {
box-sizing: border-box;
width: 350px;
height: 270px;
background: #fff;
margin: 24px auto;
z-index: 11;
position: relative;
padding: 0 15px;
user-select: none;
border-radius: 16px;
}
.framework .boxTopTitle {
height: 48px;
line-height: 48px;
display: flex;
justify-content: space-between;
}
.framework .boxImg {
height: 150px;
background: #fff;
margin-bottom: 16px;
border-radius: 8px;
position: relative;
}
.reset {
position: absolute;
top: 0;
right: 0;
padding: 0 8px;
line-height: 32px;
}
.cutImgSet {
position: absolute;
}
.frame--dialog {
.framework {
z-index: 88888888;
position: fixed;
top: 25vh;
transform: translateX(-50%);
left: 50%;
}
.frameBg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.24);
z-index: 8887 !important;
}
}
.checkBox .checkBar {
width: 100%;
padding: 0px;
}
.slide {
box-sizing: border-box;
width: 100%;
height: 40px;
line-height: 40px;
border-radius: 8px;
background-color: #FFFFFF;
position: relative;
font-size: 13px;
overflow: hidden;
border: 1px solid rgba(65, 157, 231, 0.56);
}
.moveBac {
background-color: rgba(21, 132, 223, 0.08);
width: 100%;
height: 100%;
}
.swiperBlock {
width: 40px;
height: 40px;
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
left: 0px;
top: -1px;
}
.successBlock {
background-color: #0076D6;
}
.animation {
transition: all 0.5s;
}
</style>