CaptchaVerify.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <template>
  2. <view class="captcha-verify-container">
  3. <!-- 滑动验证 -->
  4. <view class="slide-verify">
  5. <view class="slide-track">
  6. <view
  7. class="slide-thumb"
  8. :class="{ 'success': verified }"
  9. :style="{ left: thumbPosition + 'px' }"
  10. @touchstart="touchStartHandler"
  11. @touchmove="touchMoveHandler"
  12. @touchend="touchEndHandler"
  13. >
  14. <view class="slide-icon">
  15. <text v-if="verified">✓</text>
  16. <text v-else>→</text>
  17. </view>
  18. </view>
  19. <view class="slide-text">{{ verified ? '验证通过' : '向右滑动完成验证' }}</view>
  20. </view>
  21. </view>
  22. </view>
  23. </template>
  24. <script>
  25. export default {
  26. name: 'CaptchaVerify',
  27. data() {
  28. return {
  29. // 滑动验证相关
  30. verified: false,
  31. thumbPosition: 0,
  32. startX: 0,
  33. trackWidth: 0,
  34. thumbWidth: 0
  35. }
  36. },
  37. mounted() {
  38. this.initVerify();
  39. },
  40. methods: {
  41. // 初始化验证
  42. initVerify() {
  43. this.initSlideVerify();
  44. },
  45. // 滑动验证初始化
  46. initSlideVerify() {
  47. const query = uni.createSelectorQuery().in(this);
  48. query.select('.slide-track').boundingClientRect(data => {
  49. this.trackWidth = data.width;
  50. }).exec();
  51. query.select('.slide-thumb').boundingClientRect(data => {
  52. this.thumbWidth = data.width;
  53. }).exec();
  54. this.thumbPosition = 0;
  55. this.verified = false;
  56. },
  57. // 滑动开始
  58. touchStartHandler(e) {
  59. if (this.verified) return;
  60. this.startX = e.changedTouches[0].clientX;
  61. },
  62. // 滑动中
  63. touchMoveHandler(e) {
  64. if (this.verified) return;
  65. let currentX = e.changedTouches[0].clientX;
  66. let moveX = currentX - this.startX;
  67. // 限制滑块在轨道内
  68. if (moveX < 0) {
  69. moveX = 0;
  70. } else if (moveX > this.trackWidth - this.thumbWidth) {
  71. moveX = this.trackWidth - this.thumbWidth;
  72. }
  73. this.thumbPosition = moveX;
  74. },
  75. // 滑动结束
  76. touchEndHandler() {
  77. if (this.verified) return;
  78. // 验证是否滑动到末端
  79. if (this.thumbPosition >= this.trackWidth - this.thumbWidth - 5) {
  80. this.verified = true;
  81. this.$emit('verify-success');
  82. } else {
  83. // 未滑到末端,复位
  84. this.thumbPosition = 0;
  85. }
  86. }
  87. }
  88. }
  89. </script>
  90. <style lang="scss" scoped>
  91. .captcha-verify-container {
  92. width: 75%; /* 减小六分之一 */
  93. padding: 15rpx;
  94. box-sizing: border-box;
  95. margin: 0 auto; /* 水平居中 */
  96. // 滑动验证样式
  97. .slide-verify {
  98. width: 100%;
  99. height: 90rpx; /* 再增高五分之一 */
  100. position: relative;
  101. .slide-track {
  102. width: 100%;
  103. height: 90rpx; /* 增高到90rpx */
  104. background-color: #E8F1FF; /* 浅蓝色背景 */
  105. border-radius: 45rpx; /* 更新圆角 */
  106. position: relative;
  107. box-shadow: 0 2rpx 8rpx rgba(51, 133, 255, 0.2); /* 添加蓝色阴影 */
  108. border: 1rpx solid #BBDEFB; /* 添加边框 */
  109. .slide-thumb {
  110. position: absolute;
  111. top: 0;
  112. left: 0;
  113. width: 90rpx; /* 调整宽度与高度一致 */
  114. height: 90rpx; /* 增高到90rpx */
  115. border-radius: 45rpx; /* 更新圆角 */
  116. background: linear-gradient(90deg, #4285F4, #3385ff); /* 更亮丽的蓝色渐变 */
  117. z-index: 2;
  118. display: flex;
  119. align-items: center;
  120. justify-content: center;
  121. transition: background 0.3s;
  122. box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.2); /* 添加滑块阴影 */
  123. &.success {
  124. background: linear-gradient(90deg, #5CB85C, #4CAF50); /* 更亮丽的绿色渐变 */
  125. }
  126. .slide-icon {
  127. color: #fff;
  128. font-size: 36rpx; /* 调整字体 */
  129. }
  130. }
  131. .slide-text {
  132. position: absolute;
  133. width: 100%;
  134. height: 100%;
  135. line-height: 90rpx; /* 调整行高 */
  136. text-align: center;
  137. color: #5E91E5; /* 蓝色文字 */
  138. font-size: 28rpx; /* 调整字体大小 */
  139. z-index: 1;
  140. font-weight: 500; /* 稍微加粗文字 */
  141. }
  142. }
  143. }
  144. }
  145. </style>