slider-captcha-sdk 1.0.18 → 1.0.20

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
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样式为独立方法,减少主体代码长度
@@ -40,7 +40,6 @@ class PopupSliderCaptcha {
40
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',
@@ -50,7 +49,6 @@ class PopupSliderCaptcha {
50
49
  }
51
50
 
52
51
  constructor(options = {}) {
53
- // 优化:合并默认配置,使用常量
54
52
  this.options = {
55
53
  ...PopupSliderCaptcha.DEFAULTS,
56
54
  ...options,
@@ -59,7 +57,6 @@ class PopupSliderCaptcha {
59
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,
@@ -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
 
@@ -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
- if (className) element.className = className;
157
- if (textContent) element.textContent = textContent;
149
+ if (className) { element.className = className; }
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
 
@@ -177,19 +169,10 @@ class PopupSliderCaptcha {
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) => {
213
- if (e.target === elements.overlay && this.options.clickMaskClose) this.hide();
192
+ this.addEventListener(elements.closeBtn, 'click', () => this.hide());
193
+ this.addEventListener(elements.refreshBtn, 'click', () => this.refresh());
194
+ this.addEventListener(elements.overlay, 'click', (e) => {
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
  }
@@ -229,19 +211,18 @@ class PopupSliderCaptcha {
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
- if (!element || typeof handler !== 'function') return
225
+ if (!element || typeof handler !== 'function') { return }
245
226
 
246
227
  element.addEventListener(event, handler, options);
247
228
  this.eventListeners.push({ element, event, handler, options });
@@ -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;
@@ -278,9 +258,8 @@ class PopupSliderCaptcha {
278
258
  return Math.round(percentage * (this.options.width - this.options.sliderSize))
279
259
  }
280
260
 
281
- // 优化:简化拖拽处理
282
261
  handleStart(e) {
283
- if (!this.captchaData || this.state.isDragging || this.state.isLoading) return
262
+ if (!this.captchaData || this.state.isDragging || this.state.isLoading) { return }
284
263
 
285
264
  e.preventDefault();
286
265
  this.state.isDragging = true;
@@ -289,12 +268,12 @@ 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
 
296
275
  handleMove(e) {
297
- if (!this.state.isDragging) return
276
+ if (!this.state.isDragging) { return }
298
277
  e.preventDefault();
299
278
 
300
279
  const clientX = this.getClientX(e);
@@ -305,12 +284,14 @@ class PopupSliderCaptcha {
305
284
  this.times.push({ time: Date.now(), position: this.getPosition() });
306
285
 
307
286
  // 优化:使用RAF批量更新
308
- this.rafId && cancelAnimationFrame(this.rafId);
287
+ if (this.rafId) {
288
+ cancelAnimationFrame(this.rafId);
289
+ }
309
290
  this.rafId = requestAnimationFrame(() => this.updateSliderPosition());
310
291
  }
311
292
 
312
293
  handleEnd() {
313
- if (!this.state.isDragging) return
294
+ if (!this.state.isDragging) { return }
314
295
 
315
296
  this.times.push({ time: Date.now(), position: this.getPosition() });
316
297
  this.state.isDragging = false;
@@ -331,11 +312,11 @@ class PopupSliderCaptcha {
331
312
  }
332
313
 
333
314
  getClientX(e) {
334
- return e.type.includes("touch") ? e.touches[0].clientX : e.clientX
315
+ return e.type.includes('touch') ? e.touches[0].clientX : e.clientX
335
316
  }
336
317
 
337
318
  setTransition(enabled) {
338
- const transition = enabled ? "all 0.3s ease" : "none";
319
+ const transition = enabled ? 'all 0.3s ease' : 'none';
339
320
  requestAnimationFrame(() => {
340
321
  this.elements.btn.style.transition = transition;
341
322
  this.elements.sliderImg.style.transition = transition;
@@ -347,38 +328,38 @@ class PopupSliderCaptcha {
347
328
  const { elements } = this;
348
329
  const updates = {
349
330
  dragging: () => {
350
- elements.hint.style.opacity = "0";
351
- elements.fingerAnimation.style.display = "none";
331
+ elements.hint.style.opacity = '0';
332
+ elements.fingerAnimation.style.display = 'none';
352
333
  },
353
334
  success: () => {
354
- Object.assign(elements.btn.style, { background: "var(--sc-success)" });
355
- Object.assign(elements.icon.style, { innerHTML: "", color: "white" });
356
- elements.icon.innerHTML = "";
335
+ Object.assign(elements.btn.style, { background: 'var(--sc-success)' });
336
+ Object.assign(elements.icon.style, { innerHTML: '', color: 'white' });
337
+ elements.icon.innerHTML = '';
357
338
  },
358
339
  fail: () => {
359
- Object.assign(elements.btn.style, { background: "var(--sc-danger)" });
360
- Object.assign(elements.icon.style, { innerHTML: "", color: "white" });
361
- elements.icon.innerHTML = "";
340
+ Object.assign(elements.btn.style, { background: 'var(--sc-danger)' });
341
+ Object.assign(elements.icon.style, { innerHTML: '', color: 'white' });
342
+ elements.icon.innerHTML = '';
362
343
  },
363
344
  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)");
345
+ Object.assign(elements.btn.style, { background: 'white' });
346
+ Object.assign(elements.icon.style, { color: '#666' });
347
+ elements.icon.innerHTML = '';
348
+ elements.fingerAnimation.style.display = 'block';
349
+ this.updateHintText('向右滑动完成验证', 'var(--sc-text-light)');
369
350
  },
370
351
  loading: () => {
371
- elements.hint.style.opacity = "0";
372
- elements.fingerAnimation.style.display = "none";
373
- Object.assign(elements.track.style, { pointerEvents: "none", opacity: "0.6" });
352
+ elements.hint.style.opacity = '0';
353
+ elements.fingerAnimation.style.display = 'none';
354
+ Object.assign(elements.track.style, { pointerEvents: 'none', opacity: '0.6' });
374
355
  }
375
356
  };
376
357
 
377
358
  if (updates[state]) {
378
359
  requestAnimationFrame(() => {
379
360
  updates[state]();
380
- if (state !== "loading") {
381
- Object.assign(elements.track.style, { pointerEvents: "auto", opacity: "1" });
361
+ if (state !== 'loading') {
362
+ Object.assign(elements.track.style, { pointerEvents: 'auto', opacity: '1' });
382
363
  }
383
364
  });
384
365
  }
@@ -387,7 +368,7 @@ class PopupSliderCaptcha {
387
368
  updateHintText(text, color) {
388
369
  requestAnimationFrame(() => {
389
370
  Object.assign(this.elements.hint, { textContent: text });
390
- Object.assign(this.elements.hint.style, { color, opacity: "1" });
371
+ Object.assign(this.elements.hint.style, { color, opacity: '1' });
391
372
  });
392
373
  }
393
374
 
@@ -400,18 +381,18 @@ class PopupSliderCaptcha {
400
381
  requestAnimationFrame(() => {
401
382
  elements.btn.style.transform = `translateX(${state.currentX}px)`;
402
383
  elements.sliderImg.style.transform = `translateX(${pieceX}px)`;
403
- elements.fingerAnimation.style.opacity = progress >= 0.8 ? "0" : "0.6";
384
+ elements.fingerAnimation.style.opacity = progress >= 0.8 ? '0' : '0.6';
404
385
  });
405
386
  }
406
387
 
407
388
  // 优化:简化显示/隐藏逻辑
408
389
  show() {
409
390
  this.state.isVisible = true;
410
- this.elements.overlay.style.display = "flex";
391
+ this.elements.overlay.style.display = 'flex';
411
392
 
412
393
  requestAnimationFrame(() => {
413
- this.elements.overlay.classList.add("show");
414
- this.elements.modal.classList.add("show");
394
+ this.elements.overlay.classList.add('show');
395
+ this.elements.modal.classList.add('show');
415
396
  });
416
397
 
417
398
  this.loadCaptcha();
@@ -419,11 +400,11 @@ class PopupSliderCaptcha {
419
400
 
420
401
  hide() {
421
402
  this.state.isVisible = false;
422
- this.elements.overlay.classList.remove("show");
423
- this.elements.modal.classList.remove("show");
403
+ this.elements.overlay.classList.remove('show');
404
+ this.elements.modal.classList.remove('show');
424
405
 
425
406
  this.safeSetTimeout(() => {
426
- this.elements.overlay.style.display = "none";
407
+ this.elements.overlay.style.display = 'none';
427
408
  document.body.removeChild(this.elements.overlay);
428
409
  this.reset();
429
410
  this.options.onClose?.();
@@ -469,9 +450,9 @@ class PopupSliderCaptcha {
469
450
  this.abortController = new AbortController();
470
451
 
471
452
  const response = await fetch(this.options.apiUrl, {
472
- method: "POST",
453
+ method: 'POST',
473
454
  headers: {
474
- "Content-Type": "application/json",
455
+ 'Content-Type': 'application/json',
475
456
  ...this.options.headers
476
457
  },
477
458
  body: JSON.stringify({
@@ -489,7 +470,7 @@ class PopupSliderCaptcha {
489
470
 
490
471
  // 优化:更严格的数据验证
491
472
  if (!this.validateCaptchaData(data)) {
492
- throw new Error("验证码数据格式错误")
473
+ throw new Error('验证码数据格式错误')
493
474
  }
494
475
 
495
476
  this.captchaData = data.data;
@@ -498,7 +479,10 @@ class PopupSliderCaptcha {
498
479
  } catch (error) {
499
480
  if (error.name === 'AbortError') {
500
481
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR, '请求被取消');
501
- } else if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) {
482
+ } else if (
483
+ error.message.includes('Failed to fetch') ||
484
+ error.message.includes('NetworkError')
485
+ ) {
502
486
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.NETWORK_ERROR, '网络连接失败');
503
487
  } else {
504
488
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.CAPTCHA_DATA_ERROR, error.message, error);
@@ -508,12 +492,21 @@ class PopupSliderCaptcha {
508
492
 
509
493
  // 优化:添加验证码数据验证方法
510
494
  validateCaptchaData(data) {
511
- if (!data || typeof data !== 'object') return false
512
-
513
- const requiredFields = ['canvasSrc', 'blockSrc', 'canvasWidth', 'canvasHeight', 'blockWidth', 'blockHeight', 'blockY', 'nonceStr'];
495
+ if (!data || typeof data !== 'object') { return false }
496
+
497
+ const requiredFields = [
498
+ 'canvasSrc',
499
+ 'blockSrc',
500
+ 'canvasWidth',
501
+ 'canvasHeight',
502
+ 'blockWidth',
503
+ 'blockHeight',
504
+ 'blockY',
505
+ 'nonceStr'
506
+ ];
514
507
  const dataObj = data.data || data;
515
508
 
516
- return requiredFields.every(field => {
509
+ return requiredFields.every((field) => {
517
510
  const value = dataObj[field];
518
511
  return value !== null && value !== undefined && value !== ''
519
512
  })
@@ -523,6 +516,22 @@ class PopupSliderCaptcha {
523
516
  return new Promise((resolve, reject) => {
524
517
  let hasError = false;
525
518
 
519
+ // const _onLoad = () => {
520
+ // if (hasError) { return }
521
+ // loadedCount++
522
+ // if (loadedCount === 2) {
523
+ // this.hideLoading()
524
+ // resolve()
525
+ // }
526
+ // }
527
+ //
528
+ // const _onError = (error) => {
529
+ // if (hasError) { return }
530
+ // hasError = true
531
+ // this.handleError(PopupSliderCaptcha.ERROR_TYPES.IMAGE_LOAD_ERROR, '图片加载失败', error)
532
+ // reject(new Error('图片加载失败'))
533
+ // }
534
+
526
535
  // 优化:并行加载图片,提高性能
527
536
  const loadPromises = [
528
537
  this.loadImageAsync(this.elements.backgroundImg, this.captchaData.canvasSrc, {
@@ -569,16 +578,16 @@ class PopupSliderCaptcha {
569
578
  reject(new Error('图片加载超时'));
570
579
  }, 10000); // 10秒超时
571
580
 
572
- imgElement.onload = () => {
581
+ imgElement.onload = function onImageLoad() {
573
582
  this.safeClearTimeout(timeoutId);
574
583
  this.imageCache.set(src, imgElement.cloneNode());
575
584
  resolve();
576
- };
585
+ }.bind(this);
577
586
 
578
- imgElement.onerror = (error) => {
587
+ imgElement.onerror = function onImageError(error) {
579
588
  this.safeClearTimeout(timeoutId);
580
589
  reject(error);
581
- };
590
+ }.bind(this);
582
591
 
583
592
  imgElement.src = src;
584
593
  this.applyStyles(imgElement, styles);
@@ -588,7 +597,7 @@ class PopupSliderCaptcha {
588
597
  // 优化:提取样式应用逻辑
589
598
  applyStyles(element, styles) {
590
599
  Object.entries(styles).forEach(([key, value]) => {
591
- element.style[key] = typeof value === "number" ? value + "px" : value;
600
+ element.style[key] = typeof value === 'number' ? `${value}px` : value;
592
601
  });
593
602
  }
594
603
 
@@ -596,31 +605,31 @@ class PopupSliderCaptcha {
596
605
  showLoading() {
597
606
  this.state.isLoading = true;
598
607
  this.batchUpdateStyles({
599
- container: { display: "block" },
600
- loadingText: { display: "flex" },
601
- error: { display: "none" }
608
+ container: { display: 'block' },
609
+ loadingText: { display: 'flex' },
610
+ error: { display: 'none' }
602
611
  });
603
- this.updateUIState("loading");
612
+ this.updateUIState('loading');
604
613
  }
605
614
 
606
615
  hideLoading() {
607
616
  this.state.isLoading = false;
608
- this.batchUpdateStyles({ loadingText: { display: "none" } });
609
- this.updateUIState("reset");
617
+ this.batchUpdateStyles({ loadingText: { display: 'none' } });
618
+ this.updateUIState('reset');
610
619
  }
611
620
 
612
621
  showCaptcha() {
613
622
  this.batchUpdateStyles({
614
- container: { display: "block" },
615
- track: { display: "block" },
616
- error: { display: "none" }
623
+ container: { display: 'block' },
624
+ track: { display: 'block' },
625
+ error: { display: 'none' }
617
626
  });
618
627
  }
619
628
 
620
629
  showError(message) {
621
630
  this.hideLoading();
622
631
  this.batchUpdateStyles({
623
- error: { display: "block", textContent: message }
632
+ error: { display: 'block', textContent: message }
624
633
  });
625
634
  }
626
635
 
@@ -644,7 +653,7 @@ class PopupSliderCaptcha {
644
653
 
645
654
  async verify() {
646
655
  if (!this.captchaData) {
647
- this.onVerifyFail("验证码数据丢失");
656
+ this.onVerifyFail('验证码数据丢失');
648
657
  return
649
658
  }
650
659
 
@@ -656,9 +665,9 @@ class PopupSliderCaptcha {
656
665
  this.abortController = new AbortController();
657
666
 
658
667
  const response = await fetch(this.options.verifyUrl, {
659
- method: "POST",
668
+ method: 'POST',
660
669
  headers: {
661
- "Content-Type": "application/json",
670
+ 'Content-Type': 'application/json',
662
671
  ...this.options.headers
663
672
  },
664
673
  body: JSON.stringify({
@@ -682,12 +691,15 @@ class PopupSliderCaptcha {
682
691
  if (this.isVerifySuccess(data)) {
683
692
  this.onVerifySuccess(data.data || data.result);
684
693
  } else {
685
- this.onVerifyFail(data.message || data.msg || "验证失败,请重试!");
694
+ this.onVerifyFail(data.message || data.msg || '验证失败,请重试!');
686
695
  }
687
696
  } catch (error) {
688
697
  if (error.name === 'AbortError') {
689
698
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.TIMEOUT_ERROR, '验证请求被取消');
690
- } else if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) {
699
+ } else if (
700
+ error.message.includes('Failed to fetch') ||
701
+ error.message.includes('NetworkError')
702
+ ) {
691
703
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.NETWORK_ERROR, '网络连接失败');
692
704
  } else {
693
705
  this.handleError(PopupSliderCaptcha.ERROR_TYPES.VALIDATION_ERROR, error.message, error);
@@ -697,30 +709,32 @@ class PopupSliderCaptcha {
697
709
 
698
710
  // 优化:添加验证成功判断方法
699
711
  isVerifySuccess(data) {
700
- if (!data || typeof data !== 'object') return false
712
+ if (!data || typeof data !== 'object') { return false }
701
713
 
702
714
  // 支持多种成功标识
703
715
  const successIndicators = [
704
- data.code === "0",
716
+ data.code === '0',
705
717
  data.code === 0,
706
718
  data.success === true,
707
719
  data.status === 'success',
708
720
  data.result === true
709
721
  ];
710
722
 
711
- return successIndicators.some(indicator => indicator === true)
723
+ return successIndicators.some((indicator) => indicator === true)
712
724
  }
713
725
 
714
726
  onVerifySuccess(ticket) {
715
- const duration = this.dragStartTime ? Date.now() - this.dragStartTime : (Date.now() - this.startTime);
727
+ const duration = this.dragStartTime ?
728
+ Date.now() - this.dragStartTime :
729
+ Date.now() - this.startTime;
716
730
  const durationText = `验证成功!耗时:${(duration / 1000).toFixed(2)}s`;
717
731
 
718
- this.updateUIState("success");
719
- this.showFloatingTime(durationText, "success");
732
+ this.updateUIState('success');
733
+ this.showFloatingTime(durationText, 'success');
720
734
 
721
735
  this.safeSetTimeout(() => {
722
736
  this.options.onSuccess?.({
723
- ticket: ticket,
737
+ ticket,
724
738
  timestamp: Date.now(),
725
739
  duration
726
740
  });
@@ -728,21 +742,21 @@ class PopupSliderCaptcha {
728
742
  }, 2000);
729
743
  }
730
744
 
731
- showFloatingTime(text, type = "success") {
745
+ showFloatingTime(text, type = 'success') {
732
746
  const { elements } = this;
733
747
  elements.floatingTime.textContent = text;
734
748
  elements.floatingTime.className = `slider-captcha-floating-time ${type}`;
735
749
 
736
- this.safeSetTimeout(() => elements.floatingTime.classList.add("show"), 100);
750
+ this.safeSetTimeout(() => elements.floatingTime.classList.add('show'), 100);
737
751
  this.safeSetTimeout(() => {
738
- elements.floatingTime.className = "slider-captcha-floating-time";
752
+ elements.floatingTime.className = 'slider-captcha-floating-time';
739
753
  }, 2500); // 优化:延长显示时间,避免被reset清除
740
754
  }
741
755
 
742
756
  onVerifyFail(message) {
743
757
  this.state.retryCount++;
744
- this.updateUIState("fail");
745
- this.showFloatingTime(message, "fail");
758
+ this.updateUIState('fail');
759
+ this.showFloatingTime(message, 'fail');
746
760
 
747
761
  this.safeSetTimeout(() => {
748
762
  if (this.state.retryCount >= this.options.maxRetries) {
@@ -772,10 +786,10 @@ class PopupSliderCaptcha {
772
786
  // 重置UI
773
787
  requestAnimationFrame(() => {
774
788
  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";
789
+ this.elements.btn.style.transform = 'translateX(0px)';
790
+ this.elements.sliderImg.style.transform = 'translateX(0px)';
791
+ this.updateUIState('reset');
792
+ this.elements.error.style.display = 'none';
779
793
  });
780
794
  }
781
795
 
@@ -803,7 +817,7 @@ class PopupSliderCaptcha {
803
817
  }
804
818
 
805
819
  clearAllTimers() {
806
- this.timers.forEach(timer => {
820
+ this.timers.forEach((timer) => {
807
821
  clearTimeout(timer);
808
822
  clearInterval(timer);
809
823
  });
@@ -833,13 +847,15 @@ class PopupSliderCaptcha {
833
847
  // 工具函数:节流
834
848
  throttle(func, delay) {
835
849
  let lastCall = 0;
836
- return function (...args) {
850
+ const throttledFunction = (...args) => {
837
851
  const now = Date.now();
838
852
  if (now - lastCall >= delay) {
839
853
  lastCall = now;
840
854
  return func.apply(this, args)
841
855
  }
842
- }
856
+ return undefined
857
+ };
858
+ return throttledFunction
843
859
  }
844
860
 
845
861
  destroy() {
@@ -852,8 +868,8 @@ class PopupSliderCaptcha {
852
868
 
853
869
  // 恢复body样式
854
870
  if (document.body) {
855
- document.body.style.userSelect = "";
856
- document.body.style.cursor = "";
871
+ document.body.style.userSelect = '';
872
+ document.body.style.cursor = '';
857
873
  }
858
874
 
859
875
  // 清理所有定时器
@@ -881,7 +897,7 @@ class PopupSliderCaptcha {
881
897
  this.cachedDimensions = null;
882
898
 
883
899
  // 清空所有属性
884
- Object.keys(this).forEach(key => {
900
+ Object.keys(this).forEach((key) => {
885
901
  if (key !== 'constructor') {
886
902
  this[key] = null;
887
903
  }
@@ -908,12 +924,12 @@ class PopupSliderCaptcha {
908
924
  }
909
925
 
910
926
  // 模块导出
911
- if (typeof module !== "undefined" && module.exports) {
927
+ if (typeof module !== 'undefined' && module.exports) {
912
928
  module.exports = PopupSliderCaptcha;
913
929
  module.exports.default = PopupSliderCaptcha;
914
- } else if (typeof define === "function" && define.amd) {
930
+ } else if (typeof define === 'function' && define.amd) {
915
931
  define([], () => PopupSliderCaptcha);
916
- } else if (typeof window !== "undefined") {
932
+ } else if (typeof window !== 'undefined') {
917
933
  window.PopupSliderCaptcha = PopupSliderCaptcha;
918
934
  window.SliderCaptcha = PopupSliderCaptcha;
919
935
  }