slider-captcha-sdk 1.0.18 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,22 +8,22 @@ class PopupSliderCaptcha {
8
8
  sliderSize: 38,
9
9
  maxRetries: 3,
10
10
  timeout: 30000,
11
- apiUrl: "/api/captcha",
12
- verifyUrl: "/api/captcha/verify",
11
+ apiUrl: '/api/captcha',
12
+ verifyUrl: '/api/captcha/verify',
13
13
  throttleDelay: 16,
14
- clickMaskClose: false
14
+ clickMaskClose: false,
15
15
  }
16
16
 
17
17
  static CSS_CLASSES = {
18
- overlay: "slider-captcha-overlay",
19
- modal: "slider-captcha-modal",
20
- header: "slider-captcha-header",
21
- container: "slider-captcha-container",
22
- track: "slider-captcha-track",
23
- btn: "slider-captcha-btn",
24
- hint: "slider-captcha-hint",
25
- loading: "slider-captcha-loading",
26
- error: "slider-captcha-error"
18
+ overlay: 'slider-captcha-overlay',
19
+ modal: 'slider-captcha-modal',
20
+ header: 'slider-captcha-header',
21
+ container: 'slider-captcha-container',
22
+ track: 'slider-captcha-track',
23
+ btn: 'slider-captcha-btn',
24
+ hint: 'slider-captcha-hint',
25
+ loading: 'slider-captcha-loading',
26
+ error: 'slider-captcha-error',
27
27
  }
28
28
 
29
29
  // 优化:提取CSS样式为独立方法,减少主体代码长度
@@ -37,29 +37,26 @@ class PopupSliderCaptcha {
37
37
  MAX_RETRY_ATTEMPTS: 3,
38
38
  DEFAULT_TIMEOUT: 30000,
39
39
  FLOATING_TIME_DURATION: 2500,
40
- THROTTLE_DELAY: 16
40
+ THROTTLE_DELAY: 16,
41
41
  }
42
42
 
43
- // 优化:添加错误类型枚举
44
43
  static ERROR_TYPES = {
45
44
  NETWORK_ERROR: 'NETWORK_ERROR',
46
45
  TIMEOUT_ERROR: 'TIMEOUT_ERROR',
47
46
  VALIDATION_ERROR: 'VALIDATION_ERROR',
48
47
  IMAGE_LOAD_ERROR: 'IMAGE_LOAD_ERROR',
49
- CAPTCHA_DATA_ERROR: 'CAPTCHA_DATA_ERROR'
48
+ CAPTCHA_DATA_ERROR: 'CAPTCHA_DATA_ERROR',
50
49
  }
51
50
 
52
51
  constructor(options = {}) {
53
- // 优化:合并默认配置,使用常量
54
52
  this.options = {
55
53
  ...PopupSliderCaptcha.DEFAULTS,
56
54
  ...options,
57
55
  timeout: options.timeout || PopupSliderCaptcha.CONSTANTS.DEFAULT_TIMEOUT,
58
56
  maxRetries: options.maxRetries || PopupSliderCaptcha.CONSTANTS.MAX_RETRY_ATTEMPTS,
59
- throttleDelay: options.throttleDelay || PopupSliderCaptcha.CONSTANTS.THROTTLE_DELAY
57
+ throttleDelay: options.throttleDelay || PopupSliderCaptcha.CONSTANTS.THROTTLE_DELAY,
60
58
  };
61
59
 
62
- // 优化:初始化所有属性
63
60
  this.elements = {};
64
61
  this.state = this.createInitialState();
65
62
  this.captchaData = null;
@@ -72,10 +69,8 @@ class PopupSliderCaptcha {
72
69
  this.imageCache = new Map();
73
70
  this.abortController = null;
74
71
 
75
- // 优化:使用箭头函数绑定this,避免重复bind调用
76
72
  this.throttledHandleMove = this.throttle((e) => this.handleMove(e), this.options.throttleDelay);
77
73
 
78
- // 优化:添加错误处理
79
74
  try {
80
75
  this.init();
81
76
  } catch (error) {
@@ -84,7 +79,6 @@ class PopupSliderCaptcha {
84
79
  }
85
80
  }
86
81
 
87
- // 优化:提取初始状态创建为独立方法
88
82
  createInitialState() {
89
83
  return {
90
84
  isVisible: false,
@@ -92,7 +86,7 @@ class PopupSliderCaptcha {
92
86
  currentX: 0,
93
87
  startX: 0,
94
88
  retryCount: 0,
95
- isLoading: false
89
+ isLoading: false,
96
90
  }
97
91
  }
98
92
 
@@ -103,15 +97,14 @@ class PopupSliderCaptcha {
103
97
  }
104
98
 
105
99
  injectStyles() {
106
- if (document.querySelector("#slider-captcha-styles")) return
100
+ if (document.querySelector('#slider-captcha-styles')) return
107
101
 
108
- const style = document.createElement("style");
109
- style.id = "slider-captcha-styles";
102
+ const style = document.createElement('style');
103
+ style.id = 'slider-captcha-styles';
110
104
  style.textContent = PopupSliderCaptcha.getStyles();
111
105
  document.head.appendChild(style);
112
106
  }
113
107
 
114
- // 优化:简化元素创建逻辑
115
108
  createElements() {
116
109
  const { elements, options } = this;
117
110
 
@@ -133,7 +126,7 @@ class PopupSliderCaptcha {
133
126
  ['btn', 'div', PopupSliderCaptcha.CSS_CLASSES.btn],
134
127
  ['icon', 'div', '', '→'],
135
128
  ['hint', 'div', PopupSliderCaptcha.CSS_CLASSES.hint, '向右滑动完成验证'],
136
- ['error', 'div', PopupSliderCaptcha.CSS_CLASSES.error]
129
+ ['error', 'div', PopupSliderCaptcha.CSS_CLASSES.error],
137
130
  ];
138
131
 
139
132
  // 批量创建元素
@@ -151,19 +144,18 @@ class PopupSliderCaptcha {
151
144
  this.setInitialState();
152
145
  }
153
146
 
154
- createElement(tag, className = "", textContent = "") {
147
+ createElement(tag, className = '', textContent = '') {
155
148
  const element = document.createElement(tag);
156
149
  if (className) element.className = className;
157
150
  if (textContent) element.textContent = textContent;
158
151
  return element
159
152
  }
160
153
 
161
- // 优化:简化DOM组装逻辑
162
154
  assembleDOM() {
163
155
  const { elements } = this;
164
156
 
165
157
  // 组装头部
166
- const headerButtons = this.createElement("div", "slider-captcha-header-buttons");
158
+ const headerButtons = this.createElement('div', 'slider-captcha-header-buttons');
167
159
  headerButtons.append(elements.refreshBtn, elements.closeBtn);
168
160
  elements.header.append(elements.title, headerButtons);
169
161
 
@@ -172,24 +164,15 @@ class PopupSliderCaptcha {
172
164
  elements.backgroundImg,
173
165
  elements.sliderImg,
174
166
  elements.loadingText,
175
- elements.floatingTime
167
+ elements.floatingTime,
176
168
  );
177
169
 
178
170
  // 组装滑块轨道
179
171
  elements.btn.appendChild(elements.icon);
180
- elements.track.append(
181
- elements.fingerAnimation,
182
- elements.btn,
183
- elements.hint
184
- );
172
+ elements.track.append(elements.fingerAnimation, elements.btn, elements.hint);
185
173
 
186
174
  // 组装模态框
187
- elements.modal.append(
188
- elements.header,
189
- elements.container,
190
- elements.track,
191
- elements.error
192
- );
175
+ elements.modal.append(elements.header, elements.container, elements.track, elements.error);
193
176
 
194
177
  // 组装到覆盖层
195
178
  elements.overlay.appendChild(elements.modal);
@@ -198,24 +181,23 @@ class PopupSliderCaptcha {
198
181
 
199
182
  setInitialState() {
200
183
  // 批量设置初始状态
201
- Object.assign(this.elements.container.style, { display: "none" });
202
- Object.assign(this.elements.track.style, { display: "none" });
184
+ Object.assign(this.elements.container.style, { display: 'none' });
185
+ Object.assign(this.elements.track.style, { display: 'none' });
203
186
  }
204
187
 
205
- // 优化:简化事件绑定
206
188
  bindEvents() {
207
189
  const { elements } = this;
208
190
 
209
191
  // 基础事件
210
- this.addEventListener(elements.closeBtn, "click", () => this.hide());
211
- this.addEventListener(elements.refreshBtn, "click", () => this.refresh());
212
- this.addEventListener(elements.overlay, "click", (e) => {
192
+ this.addEventListener(elements.closeBtn, 'click', () => this.hide());
193
+ this.addEventListener(elements.refreshBtn, 'click', () => this.refresh());
194
+ this.addEventListener(elements.overlay, 'click', (e) => {
213
195
  if (e.target === elements.overlay && this.options.clickMaskClose) this.hide();
214
196
  });
215
- this.addEventListener(document, "keydown", (e) => {
216
- if (e.key === "Escape" && this.state.isVisible) this.hide();
197
+ this.addEventListener(document, 'keydown', (e) => {
198
+ if (e.key === 'Escape' && this.state.isVisible) this.hide();
217
199
  });
218
- this.addEventListener(document, "visibilitychange", () => this.handleVisibilityChange());
200
+ this.addEventListener(document, 'visibilitychange', () => this.handleVisibilityChange());
219
201
 
220
202
  this.bindSliderEvents();
221
203
  }
@@ -225,21 +207,20 @@ class PopupSliderCaptcha {
225
207
  const handlers = {
226
208
  start: (e) => this.handleStart(e),
227
209
  move: this.throttledHandleMove,
228
- end: () => this.handleEnd()
210
+ end: () => this.handleEnd(),
229
211
  };
230
212
 
231
213
  // 滑块事件
232
- this.addEventListener(elements.btn, "mousedown", handlers.start);
233
- this.addEventListener(elements.btn, "touchstart", handlers.start);
234
- this.addEventListener(elements.sliderImg, "mousedown", handlers.start);
235
- this.addEventListener(elements.sliderImg, "touchstart", handlers.start);
236
- this.addEventListener(document, "mousemove", handlers.move, { passive: false });
237
- this.addEventListener(document, "touchmove", handlers.move, { passive: false });
238
- this.addEventListener(document, "mouseup", handlers.end);
239
- this.addEventListener(document, "touchend", handlers.end);
214
+ this.addEventListener(elements.btn, 'mousedown', handlers.start);
215
+ this.addEventListener(elements.btn, 'touchstart', handlers.start);
216
+ this.addEventListener(elements.sliderImg, 'mousedown', handlers.start);
217
+ this.addEventListener(elements.sliderImg, 'touchstart', handlers.start);
218
+ this.addEventListener(document, 'mousemove', handlers.move, { passive: false });
219
+ this.addEventListener(document, 'touchmove', handlers.move, { passive: false });
220
+ this.addEventListener(document, 'mouseup', handlers.end);
221
+ this.addEventListener(document, 'touchend', handlers.end);
240
222
  }
241
223
 
242
- // 优化:改进事件管理
243
224
  addEventListener(element, event, handler, options = {}) {
244
225
  if (!element || typeof handler !== 'function') return
245
226
 
@@ -258,7 +239,6 @@ class PopupSliderCaptcha {
258
239
  this.eventListeners.length = 0;
259
240
  }
260
241
 
261
- // 优化:缓存尺寸计算
262
242
  getDimensions() {
263
243
  if (!this.cachedDimensions) {
264
244
  const trackWidth = this.elements.track.offsetWidth;
@@ -266,7 +246,7 @@ class PopupSliderCaptcha {
266
246
  this.cachedDimensions = {
267
247
  trackWidth,
268
248
  btnWidth,
269
- maxX: trackWidth - btnWidth
249
+ maxX: trackWidth - btnWidth,
270
250
  };
271
251
  }
272
252
  return this.cachedDimensions
@@ -278,7 +258,6 @@ class PopupSliderCaptcha {
278
258
  return Math.round(percentage * (this.options.width - this.options.sliderSize))
279
259
  }
280
260
 
281
- // 优化:简化拖拽处理
282
261
  handleStart(e) {
283
262
  if (!this.captchaData || this.state.isDragging || this.state.isLoading) return
284
263
 
@@ -289,7 +268,7 @@ class PopupSliderCaptcha {
289
268
  this.times = [{ time: Date.now(), position: this.getPosition() }];
290
269
 
291
270
  this.setTransition(false);
292
- this.updateUIState("dragging");
271
+ this.updateUIState('dragging');
293
272
  this.cachedDimensions = null; // 清除缓存
294
273
  }
295
274
 
@@ -331,11 +310,11 @@ class PopupSliderCaptcha {
331
310
  }
332
311
 
333
312
  getClientX(e) {
334
- return e.type.includes("touch") ? e.touches[0].clientX : e.clientX
313
+ return e.type.includes('touch') ? e.touches[0].clientX : e.clientX
335
314
  }
336
315
 
337
316
  setTransition(enabled) {
338
- const transition = enabled ? "all 0.3s ease" : "none";
317
+ const transition = enabled ? 'all 0.3s ease' : 'none';
339
318
  requestAnimationFrame(() => {
340
319
  this.elements.btn.style.transition = transition;
341
320
  this.elements.sliderImg.style.transition = transition;
@@ -347,38 +326,38 @@ class PopupSliderCaptcha {
347
326
  const { elements } = this;
348
327
  const updates = {
349
328
  dragging: () => {
350
- elements.hint.style.opacity = "0";
351
- elements.fingerAnimation.style.display = "none";
329
+ elements.hint.style.opacity = '0';
330
+ elements.fingerAnimation.style.display = 'none';
352
331
  },
353
332
  success: () => {
354
- Object.assign(elements.btn.style, { background: "var(--sc-success)" });
355
- Object.assign(elements.icon.style, { innerHTML: "", color: "white" });
356
- elements.icon.innerHTML = "";
333
+ Object.assign(elements.btn.style, { background: 'var(--sc-success)' });
334
+ Object.assign(elements.icon.style, { innerHTML: '', color: 'white' });
335
+ elements.icon.innerHTML = '';
357
336
  },
358
337
  fail: () => {
359
- Object.assign(elements.btn.style, { background: "var(--sc-danger)" });
360
- Object.assign(elements.icon.style, { innerHTML: "", color: "white" });
361
- elements.icon.innerHTML = "";
338
+ Object.assign(elements.btn.style, { background: 'var(--sc-danger)' });
339
+ Object.assign(elements.icon.style, { innerHTML: '', color: 'white' });
340
+ elements.icon.innerHTML = '';
362
341
  },
363
342
  reset: () => {
364
- Object.assign(elements.btn.style, { background: "white" });
365
- Object.assign(elements.icon.style, { color: "#666" });
366
- elements.icon.innerHTML = "";
367
- elements.fingerAnimation.style.display = "block";
368
- this.updateHintText("向右滑动完成验证", "var(--sc-text-light)");
343
+ Object.assign(elements.btn.style, { background: 'white' });
344
+ Object.assign(elements.icon.style, { color: '#666' });
345
+ elements.icon.innerHTML = '';
346
+ elements.fingerAnimation.style.display = 'block';
347
+ this.updateHintText('向右滑动完成验证', 'var(--sc-text-light)');
369
348
  },
370
349
  loading: () => {
371
- elements.hint.style.opacity = "0";
372
- elements.fingerAnimation.style.display = "none";
373
- Object.assign(elements.track.style, { pointerEvents: "none", opacity: "0.6" });
374
- }
350
+ elements.hint.style.opacity = '0';
351
+ elements.fingerAnimation.style.display = 'none';
352
+ Object.assign(elements.track.style, { pointerEvents: 'none', opacity: '0.6' });
353
+ },
375
354
  };
376
355
 
377
356
  if (updates[state]) {
378
357
  requestAnimationFrame(() => {
379
358
  updates[state]();
380
- if (state !== "loading") {
381
- Object.assign(elements.track.style, { pointerEvents: "auto", opacity: "1" });
359
+ if (state !== 'loading') {
360
+ Object.assign(elements.track.style, { pointerEvents: 'auto', opacity: '1' });
382
361
  }
383
362
  });
384
363
  }
@@ -387,7 +366,7 @@ class PopupSliderCaptcha {
387
366
  updateHintText(text, color) {
388
367
  requestAnimationFrame(() => {
389
368
  Object.assign(this.elements.hint, { textContent: text });
390
- Object.assign(this.elements.hint.style, { color, opacity: "1" });
369
+ Object.assign(this.elements.hint.style, { color, opacity: '1' });
391
370
  });
392
371
  }
393
372
 
@@ -400,18 +379,18 @@ class PopupSliderCaptcha {
400
379
  requestAnimationFrame(() => {
401
380
  elements.btn.style.transform = `translateX(${state.currentX}px)`;
402
381
  elements.sliderImg.style.transform = `translateX(${pieceX}px)`;
403
- elements.fingerAnimation.style.opacity = progress >= 0.8 ? "0" : "0.6";
382
+ elements.fingerAnimation.style.opacity = progress >= 0.8 ? '0' : '0.6';
404
383
  });
405
384
  }
406
385
 
407
386
  // 优化:简化显示/隐藏逻辑
408
387
  show() {
409
388
  this.state.isVisible = true;
410
- this.elements.overlay.style.display = "flex";
389
+ this.elements.overlay.style.display = 'flex';
411
390
 
412
391
  requestAnimationFrame(() => {
413
- this.elements.overlay.classList.add("show");
414
- this.elements.modal.classList.add("show");
392
+ this.elements.overlay.classList.add('show');
393
+ this.elements.modal.classList.add('show');
415
394
  });
416
395
 
417
396
  this.loadCaptcha();
@@ -419,11 +398,11 @@ class PopupSliderCaptcha {
419
398
 
420
399
  hide() {
421
400
  this.state.isVisible = false;
422
- this.elements.overlay.classList.remove("show");
423
- this.elements.modal.classList.remove("show");
401
+ this.elements.overlay.classList.remove('show');
402
+ this.elements.modal.classList.remove('show');
424
403
 
425
404
  this.safeSetTimeout(() => {
426
- this.elements.overlay.style.display = "none";
405
+ this.elements.overlay.style.display = 'none';
427
406
  document.body.removeChild(this.elements.overlay);
428
407
  this.reset();
429
408
  this.options.onClose?.();
@@ -438,7 +417,7 @@ class PopupSliderCaptcha {
438
417
  [PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR]: '请求超时,请重试',
439
418
  [PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR]: '验证失败,请重试',
440
419
  [PopupSliderCaptcha.ERROR_TYPES.IMAGE_LOAD_ERROR]: '图片加载失败,请刷新重试',
441
- [PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR]: '验证码数据错误,请刷新重试'
420
+ [PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR]: '验证码数据错误,请刷新重试',
442
421
  };
443
422
 
444
423
  const errorMessage = errorMessages[errorType] || message || '未知错误';
@@ -448,7 +427,7 @@ class PopupSliderCaptcha {
448
427
  this.options.onError({
449
428
  type: errorType,
450
429
  message: errorMessage,
451
- originalError
430
+ originalError,
452
431
  });
453
432
  }
454
433
 
@@ -469,16 +448,16 @@ class PopupSliderCaptcha {
469
448
  this.abortController = new AbortController();
470
449
 
471
450
  const response = await fetch(this.options.apiUrl, {
472
- method: "POST",
451
+ method: 'POST',
473
452
  headers: {
474
- "Content-Type": "application/json",
475
- ...this.options.headers
453
+ 'Content-Type': 'application/json',
454
+ ...this.options.headers,
476
455
  },
477
456
  body: JSON.stringify({
478
457
  timestamp: Date.now(),
479
- ...this.options.requestData
458
+ ...this.options.requestData,
480
459
  }),
481
- signal: this.abortController.signal
460
+ signal: this.abortController.signal,
482
461
  });
483
462
 
484
463
  if (!response.ok) {
@@ -489,7 +468,7 @@ class PopupSliderCaptcha {
489
468
 
490
469
  // 优化:更严格的数据验证
491
470
  if (!this.validateCaptchaData(data)) {
492
- throw new Error("验证码数据格式错误")
471
+ throw new Error('验证码数据格式错误')
493
472
  }
494
473
 
495
474
  this.captchaData = data.data;
@@ -498,7 +477,10 @@ class PopupSliderCaptcha {
498
477
  } catch (error) {
499
478
  if (error.name === 'AbortError') {
500
479
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR, '请求被取消');
501
- } else if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) {
480
+ } else if (
481
+ error.message.includes('Failed to fetch') ||
482
+ error.message.includes('NetworkError')
483
+ ) {
502
484
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.NETWORK_ERROR, '网络连接失败');
503
485
  } else {
504
486
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR, error.message, error);
@@ -510,10 +492,19 @@ class PopupSliderCaptcha {
510
492
  validateCaptchaData(data) {
511
493
  if (!data || typeof data !== 'object') return false
512
494
 
513
- const requiredFields = ['canvasSrc', 'blockSrc', 'canvasWidth', 'canvasHeight', 'blockWidth', 'blockHeight', 'blockY', 'nonceStr'];
495
+ const requiredFields = [
496
+ 'canvasSrc',
497
+ 'blockSrc',
498
+ 'canvasWidth',
499
+ 'canvasHeight',
500
+ 'blockWidth',
501
+ 'blockHeight',
502
+ 'blockY',
503
+ 'nonceStr',
504
+ ];
514
505
  const dataObj = data.data || data;
515
506
 
516
- return requiredFields.every(field => {
507
+ return requiredFields.every((field) => {
517
508
  const value = dataObj[field];
518
509
  return value !== null && value !== undefined && value !== ''
519
510
  })
@@ -527,13 +518,13 @@ class PopupSliderCaptcha {
527
518
  const loadPromises = [
528
519
  this.loadImageAsync(this.elements.backgroundImg, this.captchaData.canvasSrc, {
529
520
  width: this.captchaData.canvasWidth,
530
- height: this.captchaData.canvasHeight
521
+ height: this.captchaData.canvasHeight,
531
522
  }),
532
523
  this.loadImageAsync(this.elements.sliderImg, this.captchaData.blockSrc, {
533
524
  width: this.captchaData.blockWidth,
534
525
  height: this.captchaData.blockHeight,
535
- top: this.captchaData.blockY
536
- })
526
+ top: this.captchaData.blockY,
527
+ }),
537
528
  ];
538
529
 
539
530
  Promise.all(loadPromises)
@@ -588,7 +579,7 @@ class PopupSliderCaptcha {
588
579
  // 优化:提取样式应用逻辑
589
580
  applyStyles(element, styles) {
590
581
  Object.entries(styles).forEach(([key, value]) => {
591
- element.style[key] = typeof value === "number" ? value + "px" : value;
582
+ element.style[key] = typeof value === 'number' ? value + 'px' : value;
592
583
  });
593
584
  }
594
585
 
@@ -596,31 +587,31 @@ class PopupSliderCaptcha {
596
587
  showLoading() {
597
588
  this.state.isLoading = true;
598
589
  this.batchUpdateStyles({
599
- container: { display: "block" },
600
- loadingText: { display: "flex" },
601
- error: { display: "none" }
590
+ container: { display: 'block' },
591
+ loadingText: { display: 'flex' },
592
+ error: { display: 'none' },
602
593
  });
603
- this.updateUIState("loading");
594
+ this.updateUIState('loading');
604
595
  }
605
596
 
606
597
  hideLoading() {
607
598
  this.state.isLoading = false;
608
- this.batchUpdateStyles({ loadingText: { display: "none" } });
609
- this.updateUIState("reset");
599
+ this.batchUpdateStyles({ loadingText: { display: 'none' } });
600
+ this.updateUIState('reset');
610
601
  }
611
602
 
612
603
  showCaptcha() {
613
604
  this.batchUpdateStyles({
614
- container: { display: "block" },
615
- track: { display: "block" },
616
- error: { display: "none" }
605
+ container: { display: 'block' },
606
+ track: { display: 'block' },
607
+ error: { display: 'none' },
617
608
  });
618
609
  }
619
610
 
620
611
  showError(message) {
621
612
  this.hideLoading();
622
613
  this.batchUpdateStyles({
623
- error: { display: "block", textContent: message }
614
+ error: { display: 'block', textContent: message },
624
615
  });
625
616
  }
626
617
 
@@ -644,7 +635,7 @@ class PopupSliderCaptcha {
644
635
 
645
636
  async verify() {
646
637
  if (!this.captchaData) {
647
- this.onVerifyFail("验证码数据丢失");
638
+ this.onVerifyFail('验证码数据丢失');
648
639
  return
649
640
  }
650
641
 
@@ -656,20 +647,20 @@ class PopupSliderCaptcha {
656
647
  this.abortController = new AbortController();
657
648
 
658
649
  const response = await fetch(this.options.verifyUrl, {
659
- method: "POST",
650
+ method: 'POST',
660
651
  headers: {
661
- "Content-Type": "application/json",
662
- ...this.options.headers
652
+ 'Content-Type': 'application/json',
653
+ ...this.options.headers,
663
654
  },
664
655
  body: JSON.stringify({
665
656
  loginVo: {
666
657
  nonceStr: this.captchaData.nonceStr,
667
- value: this.getPosition()
658
+ value: this.getPosition(),
668
659
  },
669
660
  dragEventList: [...this.times],
670
- ...this.options.verifyData
661
+ ...this.options.verifyData,
671
662
  }),
672
- signal: this.abortController.signal
663
+ signal: this.abortController.signal,
673
664
  });
674
665
 
675
666
  if (!response.ok) {
@@ -682,12 +673,15 @@ class PopupSliderCaptcha {
682
673
  if (this.isVerifySuccess(data)) {
683
674
  this.onVerifySuccess(data.data || data.result);
684
675
  } else {
685
- this.onVerifyFail(data.message || data.msg || "验证失败,请重试!");
676
+ this.onVerifyFail(data.message || data.msg || '验证失败,请重试!');
686
677
  }
687
678
  } catch (error) {
688
679
  if (error.name === 'AbortError') {
689
680
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR, '验证请求被取消');
690
- } else if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) {
681
+ } else if (
682
+ error.message.includes('Failed to fetch') ||
683
+ error.message.includes('NetworkError')
684
+ ) {
691
685
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.NETWORK_ERROR, '网络连接失败');
692
686
  } else {
693
687
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR, error.message, error);
@@ -701,48 +695,50 @@ class PopupSliderCaptcha {
701
695
 
702
696
  // 支持多种成功标识
703
697
  const successIndicators = [
704
- data.code === "0",
698
+ data.code === '0',
705
699
  data.code === 0,
706
700
  data.success === true,
707
701
  data.status === 'success',
708
- data.result === true
702
+ data.result === true,
709
703
  ];
710
704
 
711
- return successIndicators.some(indicator => indicator === true)
705
+ return successIndicators.some((indicator) => indicator === true)
712
706
  }
713
707
 
714
708
  onVerifySuccess(ticket) {
715
- const duration = this.dragStartTime ? Date.now() - this.dragStartTime : (Date.now() - this.startTime);
709
+ const duration = this.dragStartTime
710
+ ? Date.now() - this.dragStartTime
711
+ : Date.now() - this.startTime;
716
712
  const durationText = `验证成功!耗时:${(duration / 1000).toFixed(2)}s`;
717
713
 
718
- this.updateUIState("success");
719
- this.showFloatingTime(durationText, "success");
714
+ this.updateUIState('success');
715
+ this.showFloatingTime(durationText, 'success');
720
716
 
721
717
  this.safeSetTimeout(() => {
722
718
  this.options.onSuccess?.({
723
719
  ticket: ticket,
724
720
  timestamp: Date.now(),
725
- duration
721
+ duration,
726
722
  });
727
723
  this.hide();
728
724
  }, 2000);
729
725
  }
730
726
 
731
- showFloatingTime(text, type = "success") {
727
+ showFloatingTime(text, type = 'success') {
732
728
  const { elements } = this;
733
729
  elements.floatingTime.textContent = text;
734
730
  elements.floatingTime.className = `slider-captcha-floating-time ${type}`;
735
731
 
736
- this.safeSetTimeout(() => elements.floatingTime.classList.add("show"), 100);
732
+ this.safeSetTimeout(() => elements.floatingTime.classList.add('show'), 100);
737
733
  this.safeSetTimeout(() => {
738
- elements.floatingTime.className = "slider-captcha-floating-time";
734
+ elements.floatingTime.className = 'slider-captcha-floating-time';
739
735
  }, 2500); // 优化:延长显示时间,避免被reset清除
740
736
  }
741
737
 
742
738
  onVerifyFail(message) {
743
739
  this.state.retryCount++;
744
- this.updateUIState("fail");
745
- this.showFloatingTime(message, "fail");
740
+ this.updateUIState('fail');
741
+ this.showFloatingTime(message, 'fail');
746
742
 
747
743
  this.safeSetTimeout(() => {
748
744
  if (this.state.retryCount >= this.options.maxRetries) {
@@ -761,7 +757,7 @@ class PopupSliderCaptcha {
761
757
  isDragging: false,
762
758
  currentX: 0,
763
759
  startX: 0,
764
- isLoading: false
760
+ isLoading: false,
765
761
  });
766
762
 
767
763
  this.times = [];
@@ -772,10 +768,10 @@ class PopupSliderCaptcha {
772
768
  // 重置UI
773
769
  requestAnimationFrame(() => {
774
770
  this.setTransition(true);
775
- this.elements.btn.style.transform = "translateX(0px)";
776
- this.elements.sliderImg.style.transform = "translateX(0px)";
777
- this.updateUIState("reset");
778
- this.elements.error.style.display = "none";
771
+ this.elements.btn.style.transform = 'translateX(0px)';
772
+ this.elements.sliderImg.style.transform = 'translateX(0px)';
773
+ this.updateUIState('reset');
774
+ this.elements.error.style.display = 'none';
779
775
  });
780
776
  }
781
777
 
@@ -803,7 +799,7 @@ class PopupSliderCaptcha {
803
799
  }
804
800
 
805
801
  clearAllTimers() {
806
- this.timers.forEach(timer => {
802
+ this.timers.forEach((timer) => {
807
803
  clearTimeout(timer);
808
804
  clearInterval(timer);
809
805
  });
@@ -852,8 +848,8 @@ class PopupSliderCaptcha {
852
848
 
853
849
  // 恢复body样式
854
850
  if (document.body) {
855
- document.body.style.userSelect = "";
856
- document.body.style.cursor = "";
851
+ document.body.style.userSelect = '';
852
+ document.body.style.cursor = '';
857
853
  }
858
854
 
859
855
  // 清理所有定时器
@@ -881,7 +877,7 @@ class PopupSliderCaptcha {
881
877
  this.cachedDimensions = null;
882
878
 
883
879
  // 清空所有属性
884
- Object.keys(this).forEach(key => {
880
+ Object.keys(this).forEach((key) => {
885
881
  if (key !== 'constructor') {
886
882
  this[key] = null;
887
883
  }
@@ -908,12 +904,12 @@ class PopupSliderCaptcha {
908
904
  }
909
905
 
910
906
  // 模块导出
911
- if (typeof module !== "undefined" && module.exports) {
907
+ if (typeof module !== 'undefined' && module.exports) {
912
908
  module.exports = PopupSliderCaptcha;
913
909
  module.exports.default = PopupSliderCaptcha;
914
- } else if (typeof define === "function" && define.amd) {
910
+ } else if (typeof define === 'function' && define.amd) {
915
911
  define([], () => PopupSliderCaptcha);
916
- } else if (typeof window !== "undefined") {
912
+ } else if (typeof window !== 'undefined') {
917
913
  window.PopupSliderCaptcha = PopupSliderCaptcha;
918
914
  window.SliderCaptcha = PopupSliderCaptcha;
919
915
  }