| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- <script lang="ts" setup>
- import { useI18n } from 'vue-i18n'
- //滑动图片验证码部分
- import Img01 from './image/verification-img-1.png'
- import Img02 from './image/verification-img-2.png'
- import Img03 from './image/verification-img-3.png'
- import Img04 from './image/verification-img-4.png'
- import { ref } from 'vue'
- //引入'vue3-puzzle-vcode'插件
- import Vcode from './components/SliderVerification.vue'
- // import Vcode from 'vue3-puzzle-vcode'
- const { t } = useI18n()
- const openDialog = () => {
- isShow.value = true
- nextTick(() => {
- addElement()
- onSuccess()
- updateSliderBackground('success')
- })
- }
- // 添加自定义元素
- const addElement = () => {
- addTipsNode()
- addSliderBtnNode('start')
- updateRefreshImg()
- }
- const updateRefreshImg = () => {
- const targetNode: any = document.querySelector('img.reset_')
- if (targetNode) {
- // 使用 import.meta.url 结合 new URL 获取图片的正确路径
- targetNode.src = new URL('./image/icon_refresh_bold_b.png', import.meta.url).href
- }
- }
- const addTipsNode = () => {
- if (document.querySelector('.v-slider-verification-tips')) {
- return
- }
- const childNode = document.createElement('div')
- childNode.className = 'v-slider-verification-tips'
- childNode.innerHTML = `
- <div style="margin-bottom: 5px; text-align: right;">
- <span class="font_family icon-icon_reject_b close-icon" style="margin-right: -20px;">
- </span>
- </div>
- <p>${t('common.sliderVerifyTipLine1')}</p>
- <p>${t('common.sliderVerifyTipLine2')}</p>
- `
- const parentNode = document.querySelector('.vue-auth-box_')
- if (parentNode.firstChild) {
- parentNode.insertBefore(childNode, parentNode.firstChild)
- } else {
- parentNode.appendChild(childNode)
- }
- nextTick(() => {
- const targetNode: any = document.querySelector('.font_family.icon-icon_reject_b.close-icon')
- targetNode.onclick = closeDialog
- })
- }
- const closeDialog = () => {
- isShow.value = false
- emit('close')
- }
- const styleMap = {
- start: {
- thumbColor: 'var(--color-slider-thumb-start)',
- 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')
- targetNode.style.background = styleMap[state].trackBackground
- }
- const emit = defineEmits<{
- close: []
- success: []
- }>()
- // 监听验证成功事件,因为这里库中的成功事件有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 === t('common.verificationSuccessful')) {
- updateSliderBackground('success')
- addSliderBtnNode('success')
- setTimeout(() => {
- emit('success')
- isShow.value = false
- }, 500)
- }
- }
- })
- })
- // 配置 MutationObserver,监听子节点的变化
- const config = { childList: true, subtree: true }
- // 启动监听
- observer.observe(targetNode, config)
- }
- }
- const close = () => {
- isShow.value = true
- emit('close')
- }
- const fail = () => {
- updateSliderBackground('error')
- addSliderBtnNode('error')
- setTimeout(() => {
- updateSliderBackground('start')
- addSliderBtnNode('start')
- }, 800)
- }
- defineExpose({
- openDialog
- })
- </script>
- <template>
- <div>
- <Vcode
- :show="isShow"
- @close="close"
- @fail="fail"
- :canvasWidth="320"
- :canvasHeight="180"
- :sliderText="t('common.swipeToVerify')"
- :sliderSize="38"
- :successText="t('common.verificationSuccessful')"
- :failText="t('common.verificationFailed')"
- :range="5"
- :imgs="[Img01, Img02, Img03, Img04]"
- ></Vcode>
- </div>
- </template>
- <style lang="scss" scoped>
- .slider-verification {
- width: 400px;
- height: 365px;
- padding: 40px;
- }
- </style>
- <style lang="scss">
- .vue-puzzle-vcode {
- // 整体框架
- div.vue-auth-box_ {
- width: 400px;
- height: 365px;
- padding: 40px;
- padding-top: 16px;
- background-color: var(--color-slider-bg);
- border-radius: 16px;
- box-shadow: -2px 2px 12px 0 rgba(0, 0, 0, 0.5);
- .v-slider-verification-tips {
- margin-bottom: 16px;
- text-align: center;
- .close-icon {
- cursor: pointer;
- &:hover {
- color: var(--color-theme);
- }
- }
- }
- .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;
- }
- }
- }
- div.vue-puzzle-vcode {
- background-color: rgba(43, 47, 54, 0.7);
- }
- .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_ {
- background: var(--color-success);
- }
- // 失败的提示
- .vue-auth-box_ .auth-body_ div.info-box_.fail {
- background: #c7353f;
- }
- .vue-auth-box_ .auth-control_ .range-box .range-slider {
- border-radius: 6px;
- }
- .vue-auth-box_ .auth-control_ div.range-box {
- border-radius: 6px;
- }
- // 滑块
- .vue-auth-box_ .auth-control_ .range-box .range-slider .range-btn {
- border-radius: 6px;
- }
- .vue-auth-box_ .auth-body_ .reset_ {
- width: 20px;
- height: 20px;
- top: 10px;
- right: 10px;
- }
- .vue-auth-box_ .auth-control_ .range-box .range-text {
- color: #fff;
- }
- }
- </style>
|