|
@@ -0,0 +1,193 @@
|
|
|
|
|
+<script lang="ts" setup>
|
|
|
|
|
+//滑动图片验证码部分
|
|
|
|
|
+import Img01 from '../image/bg.png'
|
|
|
|
|
+import { ref } from 'vue'
|
|
|
|
|
+//引入'vue3-puzzle-vcode'插件
|
|
|
|
|
+import Vcode from 'vue3-puzzle-vcode'
|
|
|
|
|
+
|
|
|
|
|
+const openDialog = () => {
|
|
|
|
|
+ isShow.value = true
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ addElement()
|
|
|
|
|
+ onSuccess()
|
|
|
|
|
+ updateSliderBackground('success')
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+// 添加自定义元素
|
|
|
|
|
+const addElement = () => {
|
|
|
|
|
+ addTipsNode()
|
|
|
|
|
+ addSliderBtnNode('start')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const addTipsNode = () => {
|
|
|
|
|
+ const childNode = document.createElement('div')
|
|
|
|
|
+ childNode.className = 'tips'
|
|
|
|
|
+ childNode.innerHTML = `
|
|
|
|
|
+ <p>Please drag the slider below to complete the</p>
|
|
|
|
|
+ <p>verification to ensure normal access</p>
|
|
|
|
|
+ `
|
|
|
|
|
+ const parentNode = document.querySelector('.vue-auth-box_')
|
|
|
|
|
+ if (parentNode.firstChild) {
|
|
|
|
|
+ parentNode.insertBefore(childNode, parentNode.firstChild)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ parentNode.appendChild(childNode)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const styleMap = {
|
|
|
|
|
+ start: {
|
|
|
|
|
+ thumbColor: 'var(--color-neutral-1)',
|
|
|
|
|
+ thumbIcon: 'icon-icon_drag__line_b',
|
|
|
|
|
+ trackBackground: '#87909e'
|
|
|
|
|
+ },
|
|
|
|
|
+ dragging: {
|
|
|
|
|
+ thumbColor: 'var(--color-neutral-1)',
|
|
|
|
|
+ thumbIcon: 'icon-icon_drag__line_b',
|
|
|
|
|
+ trackBackground: 'var(--color-success)'
|
|
|
|
|
+ },
|
|
|
|
|
+ success: {
|
|
|
|
|
+ thumbColor: '#fff',
|
|
|
|
|
+ thumbIcon: 'icon-icon_confirm_b',
|
|
|
|
|
+ trackBackground: 'var(--color-success)'
|
|
|
|
|
+ },
|
|
|
|
|
+ error: {
|
|
|
|
|
+ thumbColor: '#fff',
|
|
|
|
|
+ thumbIcon: 'icon-icon_reject_b',
|
|
|
|
|
+ trackBackground: '#c7353f'
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const addSliderBtnNode = (state: string) => {
|
|
|
|
|
+ const parentNode = document.querySelector('.range-btn')
|
|
|
|
|
+ if (state === 'start') {
|
|
|
|
|
+ parentNode.innerHTML = `
|
|
|
|
|
+ <span style="color: ${styleMap[state].thumbColor}" class="font_family ${styleMap[state].thumbIcon}"></span>
|
|
|
|
|
+ `
|
|
|
|
|
+ } else {
|
|
|
|
|
+ parentNode.innerHTML = `
|
|
|
|
|
+ <div class="icon-border" style="background: ${styleMap[state].trackBackground}">
|
|
|
|
|
+ <span style="color: ${styleMap[state].thumbColor}" class="font_family ${styleMap[state].thumbIcon}"></span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ `
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const isShow = ref(false)
|
|
|
|
|
+
|
|
|
|
|
+// 根据不同的状态,设置已滑动区域的背景颜色
|
|
|
|
|
+const updateSliderBackground = (state: string) => {
|
|
|
|
|
+ const targetNode: any = document.querySelector('.range-slider')
|
|
|
|
|
+ console.log(targetNode, styleMap[state].trackBackground)
|
|
|
|
|
+ targetNode.style.background = styleMap[state].trackBackground
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const emit = defineEmits<{
|
|
|
|
|
+ close: []
|
|
|
|
|
+}>()
|
|
|
|
|
+// 监听验证成功事件,因为这里库中的成功事件有0.8秒的延迟,所以这里手动监听验证成功事件
|
|
|
|
|
+const onSuccess = () => {
|
|
|
|
|
+ // 选择要监听的目标元素
|
|
|
|
|
+ const targetNode = document.querySelector('.info-box_') // 将此选择器替换为你的实际目标
|
|
|
|
|
+ if (targetNode) {
|
|
|
|
|
+ const observer = new MutationObserver((mutationsList) => {
|
|
|
|
|
+ mutationsList.forEach((mutation) => {
|
|
|
|
|
+ if (mutation.type === 'childList') {
|
|
|
|
|
+ if ((mutation.target as any).innerHTML === '验证通过!') {
|
|
|
|
|
+ updateSliderBackground('success')
|
|
|
|
|
+ addSliderBtnNode('success')
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ emit('close')
|
|
|
|
|
+ isShow.value = false
|
|
|
|
|
+ }, 500)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 配置 MutationObserver,监听子节点的变化
|
|
|
|
|
+ const config = { childList: true, subtree: true }
|
|
|
|
|
+
|
|
|
|
|
+ // 启动监听
|
|
|
|
|
+ observer.observe(targetNode, config)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+const close = () => {
|
|
|
|
|
+ isShow.value = true
|
|
|
|
|
+}
|
|
|
|
|
+const fail = () => {
|
|
|
|
|
+ updateSliderBackground('error')
|
|
|
|
|
+ addSliderBtnNode('error')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+defineExpose({
|
|
|
|
|
+ openDialog
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|
|
|
|
|
+<template>
|
|
|
|
|
+ <Vcode
|
|
|
|
|
+ :show="isShow"
|
|
|
|
|
+ @close="close"
|
|
|
|
|
+ @fail="fail"
|
|
|
|
|
+ :canvasWidth="320"
|
|
|
|
|
+ :canvasHeight="180"
|
|
|
|
|
+ sliderText="Swipe to verify"
|
|
|
|
|
+ :sliderSize="38"
|
|
|
|
|
+ :imgs="[Img01]"
|
|
|
|
|
+ ></Vcode>
|
|
|
|
|
+</template>
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.slider-verification {
|
|
|
|
|
+ width: 400px;
|
|
|
|
|
+ height: 373px;
|
|
|
|
|
+ padding: 40px;
|
|
|
|
|
+ .tips {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|
|
|
|
|
+<style lang="scss">
|
|
|
|
|
+// 整体框架
|
|
|
|
|
+.vue-auth-box_ {
|
|
|
|
|
+ width: 400px;
|
|
|
|
|
+ height: 373px;
|
|
|
|
|
+ padding: 40px;
|
|
|
|
|
+ .tips {
|
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ .icon-border {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ width: 16px !important;
|
|
|
|
|
+ height: 16px !important;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ border: none !important;
|
|
|
|
|
+ span {
|
|
|
|
|
+ font-size: 14px !important;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.vue-auth-box_ .auth-control_ div.range-box {
|
|
|
|
|
+ background-color: #87909e;
|
|
|
|
|
+ box-shadow: none;
|
|
|
|
|
+}
|
|
|
|
|
+.vue-auth-box_ div.auth-body_ {
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+}
|
|
|
|
|
+// 已滑动区域的样式
|
|
|
|
|
+.vue-auth-box_ .auth-control_ .range-box div.range-slider {
|
|
|
|
|
+ background-color: var(--color-success);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.vue-auth-box_ .auth-body_ div.loading-box_.hide_ {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 隐藏成功的提示
|
|
|
|
|
+.vue-auth-box_ .auth-body_ div.info-box_ {
|
|
|
|
|
+ // display: none;
|
|
|
|
|
+ opacity: 0 !important;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|