UNIVPLMDataIntegration/Web/src/components/dragVerify/dragVerifyImgRotate.vue
zuohuaijun 5074b67f65 😎初始化
2024-06-15 13:02:35 +08:00

449 lines
9.5 KiB
Vue

<template>
<div class="drag-verify-container">
<div :style="dragVerifyImgStyle" style="background-color: var(--el-color-primary)">
<img ref="checkImg" :src="imgsrc" class="check-img" :class="{goOrigin:isOk}" @load="checkimgLoaded"
:style="imgStyle" alt="">
<div class="tips success" v-if="showTips && isPassing">{{successTip}}</div>
<div class="tips danger" v-if="showTips && !isPassing && showErrorTip">{{failTip}}</div>
</div>
<div ref="dragVerify" class="drag_verify" :style="dragVerifyStyle" @mousemove="dragMoving" @mouseup="dragFinish"
@mouseleave="dragFinish" @touchmove.prevent="dragMoving" @touchend.prevent="dragFinish">
<div class="dv_progress_bar" :class="{goFirst2:isOk}" ref="progressBar" :style="progressBarStyle">
{{successMessage}}
</div>
<div class="dv_text" :style="textStyle" ref="message">
{{message}}
</div>
<div class="dv_handler dv_handler_bg" :class="{goFirst:isOk}" @mousedown="dragStart" @touchstart.prevent="dragStart"
ref="handler" :style="handlerStyle" style="background-color: var(--el-color-primary);">
<i :class="handlerIcon" style="color: #FFF;"></i>
</div>
</div>
</div>
</template>
<script lang="ts">
export default {
name: "dragVerify",
props: {
isPassing: {
type: Boolean,
default: false
},
width: {
type: Number,
default: 250
},
height: {
type: Number,
default: 40
},
text: {
type: String,
default: "swiping to the right side"
},
successText: {
type: String,
default: "success"
},
background: {
type: String,
default: "#eee"
},
progressBarBg: {
type: String,
default: "#76c61d"
},
completedBg: {
type: String,
default: "#76c61d"
},
circle: {
type: Boolean,
default: false
},
radius: {
type: String,
default: "4px"
},
handlerIcon: {
type: String
},
successIcon: {
type: String
},
handlerBg: {
type: String,
default: "#fff"
},
textSize: {
type: String,
default: "14px"
},
textColor: {
type: String,
default: "#333"
},
imgsrc: {
type: String
},
showTips: {
type: Boolean,
default: true
},
successTip: {
type: String,
default: "验证通过"
},
failTip: {
type: String,
default: "验证失败"
},
diffDegree: {
type: Number,
default: 10
},
minDegree: {
type: Number,
default: 90
},
maxDegree: {
type: Number,
default: 270
}
},
mounted: function () {
const dragEl = this.$refs.dragVerify;
dragEl.style.setProperty("--textColor", this.textColor);
dragEl.style.setProperty("--width", Math.floor(this.width / 2) + "px");
dragEl.style.setProperty("--pwidth", -Math.floor(this.width / 2) + "px");
},
computed: {
handlerStyle: function () {
return {
width: this.height + "px",
height: this.height + "px",
background: this.handlerBg
};
},
message: function () {
return this.isPassing ? "" : this.text;
},
successMessage: function () {
return this.isPassing ? this.successText : "";
},
dragVerifyStyle: function () {
return {
width: this.width + "px",
height: this.height + "px",
lineHeight: this.height + "px",
marginTop: '20px',
background: this.background,
borderRadius: this.circle ? this.height / 2 + "px" : this.radius
};
},
dragVerifyImgStyle: function () {
return {
width: this.width + "px",
height: this.width + "px",
position: "relative",
overflow: "hidden",
"border-radius": "50%"
};
},
progressBarStyle: function () {
return {
background: this.progressBarBg,
height: this.height + "px",
borderRadius: this.circle
? this.height / 2 + "px 0 0 " + this.height / 2 + "px"
: this.radius
};
},
textStyle: function () {
return {
height: this.height + "px",
width: this.width + "px",
fontSize: this.textSize
};
},
factor: function () {
//避免指定旋转角度时一直拖动到最右侧才验证通过
if (this.minDegree == this.maxDegree) {
return Math.floor(1 + Math.random() * 6) / 10 + 1;
}
return 1;
}
},
data() {
return {
isMoving: false,
x: 0,
isOk: false,
showBar: false,
showErrorTip: false,
ranRotate: 0,
cRotate: 0,
imgStyle: {}
};
},
methods: {
checkimgLoaded: function () {
//生成旋转角度
var minDegree = this.minDegree;
var maxDegree = this.maxDegree;
var ranRotate = Math.floor(
minDegree + Math.random() * (maxDegree - minDegree)
); //生成随机角度
this.ranRotate = ranRotate;
//console.log("旋转" + ranRotate);
this.imgStyle = {
transform: `rotateZ(${ranRotate}deg)`
};
},
dragStart: function (e) {
if (!this.isPassing) {
this.isMoving = true;
this.x =
(e.pageX || e.touches[0].pageX)
}
this.showBar = true;
this.showErrorTip = false;
this.$emit("handlerMove");
},
dragMoving: function (e) {
if (this.isMoving && !this.isPassing) {
var _x = (e.pageX || e.touches[0].pageX) - this.x;
//console.log(_x, "_x");
var handler = this.$refs.handler;
handler.style.left = _x + "px";
this.$refs.progressBar.style.width = _x + this.height / 2 + "px";
var cRotate = Math.ceil(
(_x / (this.width - this.height)) * this.maxDegree * this.factor
);
//console.log(cRotate, "cRotate");
this.cRotate = cRotate;
var rotate = this.ranRotate - cRotate;
this.imgStyle = {
transform: `rotateZ(${rotate}deg)`
};
}
},
dragFinish: function (e) {
if (this.isMoving && !this.isPassing) {
if (Math.abs(this.ranRotate - this.cRotate) > this.diffDegree) {
this.isOk = true;
this.imgStyle = {
transform: `rotateZ(${this.ranRotate}deg)`
};
var that = this;
setTimeout(function () {
that.$refs.handler.style.left = "0";
that.$refs.progressBar.style.width = "0";
that.isOk = false;
}, 500);
this.showErrorTip = true;
this.$emit("passfail");
} else {
this.passVerify();
}
this.isMoving = false;
}
},
passVerify: function () {
this.$emit("update:isPassing", true);
this.isMoving = false;
var handler = this.$refs.handler;
handler.children[0].className = this.successIcon;
this.$refs.progressBar.style.background = this.completedBg;
this.$refs.message.style["-webkit-text-fill-color"] = "unset";
this.$refs.message.style.animation = "slidetounlock2 3s infinite";
this.$refs.progressBar.style.color = "#fff";
this.$refs.progressBar.style.fontSize = this.textSize;
this.$emit("passcallback");
},
reset: function () {
this.reImg();
this.checkimgLoaded();
},
reImg: function () {
this.$emit("update:isPassing", false);
const oriData = this.$options.data();
for (const key in oriData) {
if (Object.prototype.hasOwnProperty.call(oriData, key)) {
this[key] = oriData[key]
}
}
var handler = this.$refs.handler;
var message = this.$refs.message;
handler.style.left = "0";
this.$refs.progressBar.style.width = "0";
handler.children[0].className = this.handlerIcon;
message.style["-webkit-text-fill-color"] = "transparent";
message.style.animation = "slidetounlock 3s infinite";
message.style.color = this.background;
},
refreshimg: function () {
this.$emit("refresh");
}
},
watch: {
imgsrc: {
immediate: false,
handler: function () {
this.reImg();
}
}
}
};
</script>
<style scoped>
.drag_verify {
position: relative;
background-color: #e8e8e8;
text-align: center;
overflow: hidden;
}
.drag_verify .dv_handler {
position: absolute;
top: 0px;
left: 0px;
cursor: move;
}
.drag_verify .dv_handler i {
color: #666;
padding-left: 0;
font-size: 16px;
}
.drag_verify .dv_handler .el-icon-circle-check {
color: #6c6;
margin-top: 9px;
}
.drag_verify .dv_progress_bar {
position: absolute;
height: 34px;
width: 0px;
}
.drag_verify .dv_text {
position: absolute;
top: 0px;
color: transparent;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
-o-user-select: none;
-ms-user-select: none;
background: -webkit-gradient(linear,
left top,
right top,
color-stop(0, var(--textColor)),
color-stop(0.4, var(--textColor)),
color-stop(0.5, #fff),
color-stop(0.6, var(--textColor)),
color-stop(1, var(--textColor)));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
-webkit-text-size-adjust: none;
animation: slidetounlock 3s infinite;
}
.drag_verify .dv_text * {
-webkit-text-fill-color: var(--textColor);
}
.goFirst {
left: 0px !important;
transition: left 0.5s;
}
.goOrigin {
transition: transform 0.5s;
}
.goKeep {
transition: left 0.2s;
}
.goFirst2 {
width: 0px !important;
transition: width 0.5s;
}
.drag-verify-container {
position: relative;
line-height: 0;
border-radius: 50%;
}
.move-bar {
position: absolute;
z-index: 100;
}
.clip-bar {
position: absolute;
background: rgba(255, 255, 255, 0.8);
}
.refresh {
position: absolute;
right: 5px;
top: 5px;
cursor: pointer;
font-size: 20px;
z-index: 200;
}
.tips {
position: absolute;
bottom: 25px;
height: 20px;
line-height: 20px;
text-align: center;
width: 100%;
font-size: 12px;
z-index: 200;
}
.tips.success {
background: rgba(255, 255, 255, 0.6);
color: green;
}
.tips.danger {
background: rgba(0, 0, 0, 0.6);
color: yellow;
}
.check-img {
width: 100%;
border-radius: 50%;
}
</style>
<style>
@-webkit-keyframes slidetounlock {
0% {
background-position: var(--pwidth) 0;
}
100% {
background-position: var(--width) 0;
}
}
@-webkit-keyframes slidetounlock2 {
0% {
background-position: var(--pwidth) 0;
}
100% {
background-position: var(--pwidth) 0;
}
}
</style>