slider-verify.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. <template>
  2. <uni-popup ref="popupRef" @change="change">
  3. <view class="popup-box">
  4. <view class="verifyBox">
  5. <view class="verify-title">
  6. <text>安全验证</text>
  7. <text @click.stop="$refs.popupRef.close()" class="verify-close iconfont">&#xe605;</text>
  8. </view>
  9. <view class="verify-hint">
  10. 滑动下方滑块完成拼图
  11. </view>
  12. <view class="slide-content">
  13. <view class="slider-pintu">
  14. <image id="pintuImg" src="@/static/logo.png" class="pintu">
  15. </image>
  16. <!-- <image id="pintuImg" :src="'@/static/images/slider-verify/' + img + '.png'" class="pintu">
  17. </image> -->
  18. <view class="pintukuai" :style="{ top: top + 'px', left: oldx + 'px' }">
  19. <image src="@/static/logo.png" :style="{ top: '-' + top + 'px', left: '-' + left + 'px'}">
  20. </image>
  21. </view>
  22. <view class="yinying" :style="{ top: top + 'px', left: left + 'px' }"></view>
  23. <view class="slider-success" v-show="moveSuccess">
  24. <text class="slider-success-icon iconfont">&#xe627;</text>
  25. <text class="slider-success-text">只用了{{ moveTime }}S,简直比闪电还快</text>
  26. </view>
  27. </view>
  28. <view class="slider-movearea" @touchend="endTouchMove">
  29. <movable-area :animation="true">
  30. <movable-view :x="x" direction="horizontal" @change="startMove">
  31. <text class="movable-item"></text>
  32. <text class="movable-item"></text>
  33. <text class="movable-item"></text>
  34. </movable-view>
  35. </movable-area>
  36. <view class="huadao"></view>
  37. </view>
  38. </view>
  39. <view class="slider-btn-group">
  40. <text class="slider-err"> {{ sliderErrText }} </text>
  41. <view class="slide-btn-refresh iconfont" @tap="refreshVerify">&#xec08;</view>
  42. </view>
  43. </view>
  44. </view>
  45. </uni-popup>
  46. </template>
  47. <script>
  48. export default {
  49. data() {
  50. return {
  51. x: 0, //初始距离
  52. oldx: 0, //移动的距离
  53. img: 'logo', //显示哪张图片
  54. left: 0, //随机拼图的最终X轴距离
  55. top: 0, //拼图的top距离
  56. moveTime: 0,
  57. moveInterval: null,
  58. moveSuccess: false,
  59. sliderErrText: '',
  60. };
  61. },
  62. mounted() {
  63. var that = this;
  64. that.refreshVerify();
  65. },
  66. methods: {
  67. open() {
  68. this.refreshVerify();
  69. this.$nextTick(() => {
  70. this.$refs.popupRef.open();
  71. })
  72. },
  73. //刷新验证
  74. refreshVerify() {
  75. this.moveSuccess = false;
  76. this.sliderErrText = '';
  77. this.clearMoveTime()
  78. var gl = Math.random().toFixed(2);
  79. const leftNum = uni.upx2px(560) * gl > uni.upx2px(280) ? uni.upx2px(280) : uni.upx2px(560) * gl + uni.upx2px(
  80. 150); //生成随机X轴最终距离
  81. this.top = uni.upx2px(190) * gl; //生成随机Y轴初始距离
  82. const maxLeft = uni.upx2px(560) - uni.upx2px(90) - uni.upx2px(70)
  83. this.left = leftNum > maxLeft ? maxLeft : leftNum
  84. if (gl <= 0.2) {
  85. this.img = 1;
  86. }
  87. if (gl > 0.2 && gl <= 0.4) {
  88. this.img = 2;
  89. }
  90. if (gl > 0.4 && gl <= 0.6) {
  91. this.img = 3;
  92. }
  93. if (gl > 0.6 && gl <= 0.8) {
  94. this.img = 4;
  95. }
  96. if (gl > 0.8 && gl <= 1) {
  97. this.img = 5;
  98. }
  99. this.resetMove(); //重置阴影位置
  100. },
  101. /* 滑动中 */
  102. startMove(e) {
  103. if (e.detail.source) {
  104. this.setMoveTime();
  105. const maxNum = uni.upx2px(560) - uni.upx2px(70)
  106. if (e.detail.x <= maxNum) {
  107. this.oldx = e.detail.x;
  108. }
  109. };
  110. },
  111. setMoveTime(clear = false) {
  112. if (!this.moveInterval) {
  113. this.moveTime = 0;
  114. this.moveInterval = setInterval(() => {
  115. this.moveTime = Math.floor((this.moveTime + 0.1) * 100) / 100;
  116. // console.log('this.moveTime = ', this.moveTime)
  117. }, 100)
  118. }
  119. if (clear) {
  120. try {
  121. setTimeout(() => {
  122. clearInterval(this.moveInterval)
  123. this.moveInterval = null;
  124. }, 100)
  125. // console.log('this.moveInterval 1= ', this.moveInterval)
  126. // console.log('this.moveInterval 2= ', this.moveInterval)
  127. } catch {}
  128. }
  129. },
  130. clearMoveTime() {
  131. this.setMoveTime(true);
  132. },
  133. change(e){
  134. this.$emit('change' , e.show)
  135. console.log('change = ' ,e.show)
  136. },
  137. /* 滑动结束 */
  138. endTouchMove() {
  139. var that = this;
  140. this.clearMoveTime()
  141. if (Math.abs(that.oldx - that.left) <= 5) {
  142. // uni.showToast({
  143. // title: '验证成功',
  144. // duration: 2500,
  145. // success() {
  146. // that.$emit('touchSliderResult', true);
  147. // }
  148. // });
  149. this.moveSuccess = true;
  150. setTimeout(() => {
  151. this.$refs.popupRef.close();
  152. this.$emit('slideImgSuccess')
  153. },1000)
  154. } else {
  155. this.sliderErrText = '请控制拼图对齐切口'
  156. setTimeout(() => {
  157. this.sliderErrText = ''
  158. that.refreshVerify();
  159. }, 1000)
  160. }
  161. },
  162. /* 重置阴影位置 */
  163. resetMove() {
  164. this.x = 1;
  165. this.oldx = 1;
  166. setTimeout(() => {
  167. this.x = 0;
  168. this.oldx = 0;
  169. }, 300);
  170. },
  171. // 关闭
  172. closeSlider() {
  173. this.$emit('touchSliderResult', false);
  174. },
  175. }
  176. }
  177. </script>
  178. <style lang="scss" scoped>
  179. $imgSize: 80rpx;
  180. $pintuH:360rpx;
  181. .verifyBox {
  182. // position: absolute;
  183. // top: 50%;
  184. // left: 50%;
  185. // transform: translate(-50%, -50%);
  186. // width: 560rpx;
  187. background-color: #fff;
  188. border-radius: 4rpx;
  189. padding: 8px;
  190. // box-shadow: 0 0 5upx rgba(0, 0, 0);
  191. .verify-title {
  192. width: 100%;
  193. display: flex;
  194. align-items: center;
  195. justify-content: space-between;
  196. font-size: 20rpx;
  197. color: #ccc;
  198. .verify-close {
  199. font-size: 40rpx;
  200. color: #666;
  201. }
  202. }
  203. .verify-hint {
  204. font-size: 28rpx;
  205. }
  206. .slide-content {
  207. width: 100%;
  208. padding: 5px 0;
  209. margin: 0 auto;
  210. .slide-tips {
  211. font-size: 28rpx;
  212. color: rgba(2, 20, 33, 0.45);
  213. padding: 0.5em 0;
  214. }
  215. .slider-pintu {
  216. position: relative;
  217. width: 100%;
  218. border-radius: 10rpx;
  219. overflow: hidden;
  220. .pintu {
  221. width: 560rpx;
  222. height: $pintuH;
  223. display: block;
  224. margin: 0 auto;
  225. }
  226. .pintukuai {
  227. position: absolute;
  228. top: 0;
  229. left: 0;
  230. width: $imgSize;
  231. height: $imgSize;
  232. z-index: 100;
  233. box-shadow: 0 0 5upx rgba(0, 0, 0, 0.3);
  234. overflow: hidden;
  235. image {
  236. display: block;
  237. position: absolute;
  238. top: 0;
  239. left: 0;
  240. width: 560rpx;
  241. height: $pintuH;
  242. }
  243. }
  244. }
  245. .yinying {
  246. position: absolute;
  247. width: $imgSize;
  248. height: $imgSize;
  249. background-color: rgba(0, 0, 0, 0.5);
  250. }
  251. // <view class="slider-success">
  252. // <text class="slider-success-icon">&#xe627;</text>
  253. // <text class="slider-success-text">只用了2S,</text>
  254. // </view>
  255. .slider-success {
  256. width: 100%;
  257. height: 100%;
  258. position: absolute;
  259. z-index: 101;
  260. left: 0;
  261. top: 0;
  262. background-color: rgba(255, 255, 255, 0.8);
  263. display: flex;
  264. justify-content: center;
  265. align-items: center;
  266. flex-direction: column;
  267. .slider-success-icon {
  268. font-size: 80rpx;
  269. color: $Theme-Color;
  270. }
  271. .slider-success-text {
  272. padding-top: 20rpx;
  273. font-size: 26rpx;
  274. color: $Theme-Color;
  275. }
  276. }
  277. }
  278. }
  279. .slider-movearea {
  280. position: relative;
  281. height: 50rpx;
  282. width: 100%;
  283. margin: 18rpx auto;
  284. movable-area {
  285. height: 50rpx;
  286. width: calc(100% - 90rpx);
  287. movable-view {
  288. width: 90rpx;
  289. height: 50rpx;
  290. border-radius: 25rpx;
  291. background-color: #007cff;
  292. position: relative;
  293. z-index: 100;
  294. box-shadow: 0px 0px 10px -1px #007cff;
  295. display: flex;
  296. justify-content: center;
  297. align-items: center;
  298. .movable-item {
  299. width: 3rpx;
  300. height: 20rpx;
  301. background-color: #fff;
  302. margin-right: 4px;
  303. &:last-child {
  304. margin-right: 0;
  305. }
  306. }
  307. }
  308. }
  309. }
  310. .huadao {
  311. width: 100%;
  312. height: 22rpx;
  313. background: #c2c2c2;
  314. box-shadow: inset 0 0 5upx #ccc;
  315. border-radius: 40rpx;
  316. position: absolute;
  317. top: 50%;
  318. left: 0;
  319. transform: translateY(-50%);
  320. font-size: 28rpx;
  321. z-index: 99;
  322. }
  323. .slider-btn-group {
  324. width: 100%;
  325. display: flex;
  326. justify-content: space-between;
  327. align-items: center;
  328. .slider-err {
  329. font-size: 24rpx;
  330. color: red;
  331. }
  332. .slide-btn-refresh {
  333. font-size: 40rpx;
  334. color: #c1c1c1;
  335. }
  336. }
  337. </style>