@i17hush/h5-utils 1.1.1 → 1.1.2

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.
package/dist/index.esm.js CHANGED
@@ -219,15 +219,36 @@ function createTaroAdapter(taro) {
219
219
  }
220
220
 
221
221
  let currentAdapter = null;
222
+ /**
223
+ * 运行时检测是否在 Taro 环境中
224
+ * 不依赖 process.env.TARO_ENV(构建时替换,预编译库无法获取)
225
+ * 改为检测 Taro 运行时特征
226
+ */
227
+ function isTaroEnv() {
228
+ // 1. 检测小程序全局对象(微信 wx、支付宝 my、字节 tt、百度 swan、QQ qq)
229
+ if (typeof wx !== 'undefined' ||
230
+ typeof my !== 'undefined' ||
231
+ typeof tt !== 'undefined' ||
232
+ typeof swan !== 'undefined' ||
233
+ typeof qq !== 'undefined') {
234
+ return true;
235
+ }
236
+ // 2. 检测 Taro 运行时注入的全局变量
237
+ const g = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : {};
238
+ if (g.__TARO || g.__taro__) {
239
+ return true;
240
+ }
241
+ // 3. process.env.TARO_ENV 作为补充(Taro H5 模式下可能有效)
242
+ if (typeof process !== 'undefined' && process.env && process.env.TARO_ENV) {
243
+ return true;
244
+ }
245
+ return false;
246
+ }
222
247
  /**
223
248
  * 自动检测运行环境并创建对应适配器
224
249
  */
225
250
  function detectAdapter() {
226
- // Taro 构建时会注入 process.env.TARO_ENV(如 'weapp', 'h5', 'alipay' 等)
227
- const env = typeof process !== 'undefined' && process.env
228
- ? process.env.TARO_ENV
229
- : '';
230
- if (env) {
251
+ if (isTaroEnv()) {
231
252
  try {
232
253
  // eslint-disable-next-line @typescript-eslint/no-var-requires
233
254
  const Taro = require('@tarojs/taro');
@@ -255,6 +276,35 @@ function setAdapter(adapter) {
255
276
  currentAdapter = adapter;
256
277
  }
257
278
 
279
+ /**
280
+ * 内部错误处理工具
281
+ */
282
+ const PREFIX = '[h5-utils]';
283
+ /**
284
+ * 安全执行函数,出错时打印错误并返回默认值
285
+ */
286
+ function safeCall(fn, fallback, method) {
287
+ try {
288
+ return fn();
289
+ }
290
+ catch (e) {
291
+ console.error(`${PREFIX} ${method} error:`, (e === null || e === void 0 ? void 0 : e.message) || e);
292
+ return fallback;
293
+ }
294
+ }
295
+ /**
296
+ * 安全执行异步函数
297
+ */
298
+ async function safeCallAsync(fn, fallback, method) {
299
+ try {
300
+ return await fn();
301
+ }
302
+ catch (e) {
303
+ console.error(`${PREFIX} ${method} error:`, (e === null || e === void 0 ? void 0 : e.message) || e);
304
+ return fallback;
305
+ }
306
+ }
307
+
258
308
  /**
259
309
  * URL 解析与操作工具
260
310
  */
@@ -262,57 +312,63 @@ function setAdapter(adapter) {
262
312
  * 解析 URL 为结构化对象
263
313
  */
264
314
  function parseUrl(url) {
265
- const a = document.createElement('a');
266
- a.href = url;
267
- const query = {};
268
- if (a.search) {
269
- a.search
270
- .slice(1)
271
- .split('&')
272
- .forEach((pair) => {
273
- const [key, val] = pair.split('=');
274
- if (key)
275
- query[decodeURIComponent(key)] = decodeURIComponent(val || '');
276
- });
277
- }
278
- return {
279
- protocol: a.protocol,
280
- host: a.host,
281
- port: a.port,
282
- pathname: a.pathname,
283
- search: a.search,
284
- hash: a.hash,
285
- query,
286
- };
315
+ return safeCall(() => {
316
+ const a = document.createElement('a');
317
+ a.href = url;
318
+ const query = {};
319
+ if (a.search) {
320
+ a.search
321
+ .slice(1)
322
+ .split('&')
323
+ .forEach((pair) => {
324
+ const [key, val] = pair.split('=');
325
+ if (key)
326
+ query[decodeURIComponent(key)] = decodeURIComponent(val || '');
327
+ });
328
+ }
329
+ return {
330
+ protocol: a.protocol,
331
+ host: a.host,
332
+ port: a.port,
333
+ pathname: a.pathname,
334
+ search: a.search,
335
+ hash: a.hash,
336
+ query,
337
+ };
338
+ }, { protocol: '', host: '', port: '', pathname: '', search: '', hash: '', query: {} }, 'parseUrl');
287
339
  }
288
340
  /**
289
341
  * 拼接带查询参数的 URL
290
342
  */
291
343
  function buildUrl(base, params) {
292
- const search = Object.entries(params)
293
- .filter(([, v]) => v !== undefined && v !== null)
294
- .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
295
- .join('&');
296
- if (!search)
297
- return base;
298
- const separator = base.includes('?') ? '&' : '?';
299
- return `${base}${separator}${search}`;
344
+ return safeCall(() => {
345
+ const search = Object.entries(params)
346
+ .filter(([, v]) => v !== undefined && v !== null)
347
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
348
+ .join('&');
349
+ if (!search)
350
+ return base;
351
+ const separator = base.includes('?') ? '&' : '?';
352
+ return `${base}${separator}${search}`;
353
+ }, base, 'buildUrl');
300
354
  }
301
355
  /**
302
356
  * 获取当前页面指定查询参数
303
357
  */
304
358
  function getQueryParam(name) {
305
- return new URLSearchParams(window.location.search).get(name);
359
+ return safeCall(() => new URLSearchParams(window.location.search).get(name), null, 'getQueryParam');
306
360
  }
307
361
  /**
308
362
  * 获取当前页面所有查询参数
309
363
  */
310
364
  function getAllQueryParams() {
311
- const params = {};
312
- new URLSearchParams(window.location.search).forEach((value, key) => {
313
- params[key] = value;
314
- });
315
- return params;
365
+ return safeCall(() => {
366
+ const params = {};
367
+ new URLSearchParams(window.location.search).forEach((value, key) => {
368
+ params[key] = value;
369
+ });
370
+ return params;
371
+ }, {}, 'getAllQueryParams');
316
372
  }
317
373
 
318
374
  /**
@@ -324,42 +380,46 @@ function getAllQueryParams() {
324
380
  * 获取存储值,支持 JSON 自动反序列化
325
381
  */
326
382
  function get$1(key) {
327
- const raw = getAdapter().storage.get(key);
328
- if (raw === null)
329
- return null;
330
- try {
331
- const item = JSON.parse(raw);
332
- if (item.expireAt !== null && Date.now() > item.expireAt) {
333
- getAdapter().storage.remove(key);
383
+ return safeCall(() => {
384
+ const raw = getAdapter().storage.get(key);
385
+ if (raw === null)
334
386
  return null;
387
+ try {
388
+ const item = JSON.parse(raw);
389
+ if (item.expireAt !== null && Date.now() > item.expireAt) {
390
+ getAdapter().storage.remove(key);
391
+ return null;
392
+ }
393
+ return item.value;
335
394
  }
336
- return item.value;
337
- }
338
- catch (_a) {
339
- return raw;
340
- }
395
+ catch (_a) {
396
+ return raw;
397
+ }
398
+ }, null, 'getStorage');
341
399
  }
342
400
  /**
343
401
  * 设置存储值,支持过期时间
344
402
  */
345
403
  function set$1(key, value, options) {
346
- const item = {
347
- value,
348
- expireAt: (options === null || options === void 0 ? void 0 : options.expires) ? Date.now() + options.expires : null,
349
- };
350
- getAdapter().storage.set(key, JSON.stringify(item), options);
404
+ safeCall(() => {
405
+ const item = {
406
+ value,
407
+ expireAt: (options === null || options === void 0 ? void 0 : options.expires) ? Date.now() + options.expires : null,
408
+ };
409
+ getAdapter().storage.set(key, JSON.stringify(item), options);
410
+ }, undefined, 'setStorage');
351
411
  }
352
412
  /**
353
413
  * 删除存储值
354
414
  */
355
415
  function remove$1(key) {
356
- getAdapter().storage.remove(key);
416
+ safeCall(() => getAdapter().storage.remove(key), undefined, 'removeStorage');
357
417
  }
358
418
  /**
359
419
  * 清空所有存储
360
420
  */
361
421
  function clear() {
362
- getAdapter().storage.clear();
422
+ safeCall(() => getAdapter().storage.clear(), undefined, 'clearStorage');
363
423
  }
364
424
 
365
425
  /**
@@ -369,27 +429,31 @@ function clear() {
369
429
  * 获取 Cookie 值
370
430
  */
371
431
  function get(name) {
372
- const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${encodeURIComponent(name)}=([^;]*)`));
373
- return match ? decodeURIComponent(match[1]) : null;
432
+ return safeCall(() => {
433
+ const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${encodeURIComponent(name)}=([^;]*)`));
434
+ return match ? decodeURIComponent(match[1]) : null;
435
+ }, null, 'getCookie');
374
436
  }
375
437
  /**
376
438
  * 设置 Cookie
377
439
  */
378
440
  function set(name, value, options = {}) {
379
- const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
380
- if (options.days) {
381
- const expires = new Date(Date.now() + options.days * 864e5).toUTCString();
382
- parts.push(`expires=${expires}`);
383
- }
384
- if (options.path)
385
- parts.push(`path=${options.path}`);
386
- if (options.domain)
387
- parts.push(`domain=${options.domain}`);
388
- if (options.secure)
389
- parts.push('secure');
390
- if (options.sameSite)
391
- parts.push(`samesite=${options.sameSite}`);
392
- document.cookie = parts.join('; ');
441
+ safeCall(() => {
442
+ const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
443
+ if (options.days) {
444
+ const expires = new Date(Date.now() + options.days * 864e5).toUTCString();
445
+ parts.push(`expires=${expires}`);
446
+ }
447
+ if (options.path)
448
+ parts.push(`path=${options.path}`);
449
+ if (options.domain)
450
+ parts.push(`domain=${options.domain}`);
451
+ if (options.secure)
452
+ parts.push('secure');
453
+ if (options.sameSite)
454
+ parts.push(`samesite=${options.sameSite}`);
455
+ document.cookie = parts.join('; ');
456
+ }, undefined, 'setCookie');
393
457
  }
394
458
  /**
395
459
  * 删除 Cookie
@@ -405,60 +469,73 @@ function remove(name, options = {}) {
405
469
  * 是否为 iOS
406
470
  */
407
471
  function isIOS() {
408
- return getAdapter().device.getInfo().ios;
472
+ return safeCall(() => getAdapter().device.getInfo().ios, false, 'isIOS');
409
473
  }
410
474
  /**
411
475
  * 是否为 Android
412
476
  */
413
477
  function isAndroid() {
414
- return getAdapter().device.getInfo().android;
478
+ return safeCall(() => getAdapter().device.getInfo().android, false, 'isAndroid');
415
479
  }
416
480
  /**
417
481
  * 是否为微信浏览器
418
482
  */
419
483
  function isWeChat() {
420
- return getAdapter().device.getInfo().weChat;
484
+ return safeCall(() => getAdapter().device.getInfo().weChat, false, 'isWeChat');
421
485
  }
422
486
  /**
423
487
  * 是否为移动端
424
488
  */
425
489
  function isMobile() {
426
- return getAdapter().device.getInfo().mobile;
490
+ return safeCall(() => getAdapter().device.getInfo().mobile, false, 'isMobile');
427
491
  }
428
492
  /**
429
493
  * 获取浏览器类型(H5 专用)
430
494
  */
431
495
  function getBrowserType() {
432
- const ua = typeof navigator !== 'undefined' ? navigator.userAgent : '';
433
- if (/MicroMessenger/i.test(ua))
434
- return 'weixin';
435
- if (/\bQQ\//i.test(ua))
436
- return 'qq';
437
- if (/UCBrowser/i.test(ua))
438
- return 'uc';
439
- if (/Edg/i.test(ua))
440
- return 'edge';
441
- if (/Firefox/i.test(ua))
442
- return 'firefox';
443
- if (/MSIE|Trident/i.test(ua))
444
- return 'ie';
445
- if (/Chrome/i.test(ua))
446
- return 'chrome';
447
- if (/Safari/i.test(ua))
448
- return 'safari';
449
- return 'unknown';
496
+ return safeCall(() => {
497
+ const ua = typeof navigator !== 'undefined' ? navigator.userAgent : '';
498
+ if (/MicroMessenger/i.test(ua))
499
+ return 'weixin';
500
+ if (/\bQQ\//i.test(ua))
501
+ return 'qq';
502
+ if (/UCBrowser/i.test(ua))
503
+ return 'uc';
504
+ if (/Edg/i.test(ua))
505
+ return 'edge';
506
+ if (/Firefox/i.test(ua))
507
+ return 'firefox';
508
+ if (/MSIE|Trident/i.test(ua))
509
+ return 'ie';
510
+ if (/Chrome/i.test(ua))
511
+ return 'chrome';
512
+ if (/Safari/i.test(ua))
513
+ return 'safari';
514
+ return 'unknown';
515
+ }, 'unknown', 'getBrowserType');
450
516
  }
451
517
  /**
452
518
  * 获取操作系统信息
453
519
  */
454
520
  function getOS() {
455
- return getAdapter().device.getInfo().os;
521
+ return safeCall(() => getAdapter().device.getInfo().os, 'Unknown', 'getOS');
456
522
  }
457
523
  /**
458
524
  * 获取完整设备信息
459
525
  */
460
526
  function getDeviceInfo() {
461
- return getAdapter().device.getInfo();
527
+ return safeCall(() => getAdapter().device.getInfo(), {
528
+ ios: false,
529
+ android: false,
530
+ mobile: false,
531
+ weChat: false,
532
+ os: 'Unknown',
533
+ brand: '',
534
+ model: '',
535
+ screenWidth: 0,
536
+ screenHeight: 0,
537
+ pixelRatio: 1,
538
+ }, 'getDeviceInfo');
462
539
  }
463
540
 
464
541
  /**
@@ -468,53 +545,56 @@ function getDeviceInfo() {
468
545
  * 查询单个元素
469
546
  */
470
547
  function $(selector) {
471
- return getAdapter().dom.select(selector);
548
+ return safeCall(() => getAdapter().dom.select(selector), null, '$');
472
549
  }
473
550
  /**
474
551
  * 查询多个元素
475
552
  */
476
553
  function $$(selector) {
477
- return getAdapter().dom.selectAll(selector);
554
+ return safeCall(() => getAdapter().dom.selectAll(selector), [], '$$');
478
555
  }
479
556
  /**
480
557
  * 添加 class
481
558
  */
482
559
  function addClass(el, cls) {
483
- el.classList.add(cls);
560
+ safeCall(() => el.classList.add(cls), undefined, 'addClass');
484
561
  }
485
562
  /**
486
563
  * 移除 class
487
564
  */
488
565
  function removeClass(el, cls) {
489
- el.classList.remove(cls);
566
+ safeCall(() => el.classList.remove(cls), undefined, 'removeClass');
490
567
  }
491
568
  /**
492
569
  * 切换 class
493
570
  */
494
571
  function toggleClass(el, cls) {
495
- el.classList.toggle(cls);
572
+ safeCall(() => el.classList.toggle(cls), undefined, 'toggleClass');
496
573
  }
497
574
  /**
498
575
  * 判断是否包含 class
499
576
  */
500
577
  function hasClass(el, cls) {
501
- return el.classList.contains(cls);
578
+ return safeCall(() => el.classList.contains(cls), false, 'hasClass');
502
579
  }
503
580
  /**
504
581
  * 获取元素样式
505
582
  */
506
583
  function getStyle(el, prop) {
507
- return (el.style.getPropertyValue(prop) || getComputedStyle(el).getPropertyValue(prop));
584
+ return safeCall(() => el.style.getPropertyValue(prop) ||
585
+ getComputedStyle(el).getPropertyValue(prop), '', 'getStyle');
508
586
  }
509
587
  /**
510
588
  * 判断元素是否在可视区域内
511
589
  */
512
590
  function isInViewport(el) {
513
- const rect = el.getBoundingClientRect();
514
- return (rect.top >= 0 &&
515
- rect.left >= 0 &&
516
- rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
517
- rect.right <= (window.innerWidth || document.documentElement.clientWidth));
591
+ return safeCall(() => {
592
+ const rect = el.getBoundingClientRect();
593
+ return (rect.top >= 0 &&
594
+ rect.left >= 0 &&
595
+ rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
596
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth));
597
+ }, false, 'isInViewport');
518
598
  }
519
599
 
520
600
  /**
@@ -524,19 +604,19 @@ function isInViewport(el) {
524
604
  * 绑定事件
525
605
  */
526
606
  function on(el, event, handler, options) {
527
- el.addEventListener(event, handler, options);
607
+ safeCall(() => el.addEventListener(event, handler, options), undefined, 'on');
528
608
  }
529
609
  /**
530
610
  * 解绑事件
531
611
  */
532
612
  function off(el, event, handler, options) {
533
- el.removeEventListener(event, handler, options);
613
+ safeCall(() => el.removeEventListener(event, handler, options), undefined, 'off');
534
614
  }
535
615
  /**
536
616
  * 单次监听事件
537
617
  */
538
618
  function once(el, event, handler) {
539
- el.addEventListener(event, handler, { once: true });
619
+ safeCall(() => el.addEventListener(event, handler, { once: true }), undefined, 'once');
540
620
  }
541
621
  /**
542
622
  * 事件委托
@@ -546,14 +626,16 @@ function once(el, event, handler) {
546
626
  * @param handler 回调函数
547
627
  */
548
628
  function delegate(parent, selector, event, handler) {
549
- const wrappedHandler = (e) => {
550
- var _a;
551
- const target = (_a = e.target) === null || _a === void 0 ? void 0 : _a.closest(selector);
552
- if (target) {
553
- handler(target, e);
554
- }
555
- };
556
- parent.addEventListener(event, wrappedHandler);
629
+ safeCall(() => {
630
+ const wrappedHandler = (e) => {
631
+ var _a;
632
+ const target = (_a = e.target) === null || _a === void 0 ? void 0 : _a.closest(selector);
633
+ if (target) {
634
+ handler(target, e);
635
+ }
636
+ };
637
+ parent.addEventListener(event, wrappedHandler);
638
+ }, undefined, 'delegate');
557
639
  }
558
640
 
559
641
  /**
@@ -563,13 +645,13 @@ function delegate(parent, selector, event, handler) {
563
645
  * 复制文本到剪贴板
564
646
  */
565
647
  function copyText(text) {
566
- return getAdapter().clipboard.write(text);
648
+ return safeCallAsync(() => getAdapter().clipboard.write(text), undefined, 'copyText');
567
649
  }
568
650
  /**
569
651
  * 读取剪贴板文本
570
652
  */
571
653
  function readText() {
572
- return getAdapter().clipboard.read();
654
+ return safeCallAsync(() => getAdapter().clipboard.read(), '', 'readText');
573
655
  }
574
656
 
575
657
  /**
@@ -580,34 +662,40 @@ let scrollLockCount = 0;
580
662
  * 滚动到页面顶部
581
663
  */
582
664
  function scrollToTop(smooth = true) {
583
- getAdapter().scroll.scrollTo({ top: 0, animated: smooth });
665
+ safeCall(() => getAdapter().scroll.scrollTo({ top: 0, animated: smooth }), undefined, 'scrollToTop');
584
666
  }
585
667
  /**
586
668
  * 滚动到指定元素
587
669
  */
588
670
  function scrollToElement(el, options = {}) {
589
- const { offset = 0, smooth = true } = options;
590
- const rect = el.getBoundingClientRect();
591
- const top = window.scrollY + rect.top + offset;
592
- getAdapter().scroll.scrollTo({ top, animated: smooth });
671
+ safeCall(() => {
672
+ const { offset = 0, smooth = true } = options;
673
+ const rect = el.getBoundingClientRect();
674
+ const top = window.scrollY + rect.top + offset;
675
+ getAdapter().scroll.scrollTo({ top, animated: smooth });
676
+ }, undefined, 'scrollToElement');
593
677
  }
594
678
  /**
595
679
  * 锁定页面滚动
596
680
  */
597
681
  function lockScroll() {
598
- scrollLockCount++;
599
- if (scrollLockCount === 1) {
600
- getAdapter().scroll.lockScroll();
601
- }
682
+ safeCall(() => {
683
+ scrollLockCount++;
684
+ if (scrollLockCount === 1) {
685
+ getAdapter().scroll.lockScroll();
686
+ }
687
+ }, undefined, 'lockScroll');
602
688
  }
603
689
  /**
604
690
  * 解锁页面滚动
605
691
  */
606
692
  function unlockScroll() {
607
- scrollLockCount = Math.max(0, scrollLockCount - 1);
608
- if (scrollLockCount === 0) {
609
- getAdapter().scroll.unlockScroll();
610
- }
693
+ safeCall(() => {
694
+ scrollLockCount = Math.max(0, scrollLockCount - 1);
695
+ if (scrollLockCount === 0) {
696
+ getAdapter().scroll.unlockScroll();
697
+ }
698
+ }, undefined, 'unlockScroll');
611
699
  }
612
700
 
613
701
  /**
@@ -618,49 +706,53 @@ function unlockScroll() {
618
706
  * @example formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss')
619
707
  */
620
708
  function formatDate(date, fmt = 'YYYY-MM-DD HH:mm:ss') {
621
- const d = new Date(date);
622
- const map = {
623
- YYYY: String(d.getFullYear()),
624
- MM: String(d.getMonth() + 1).padStart(2, '0'),
625
- DD: String(d.getDate()).padStart(2, '0'),
626
- HH: String(d.getHours()).padStart(2, '0'),
627
- mm: String(d.getMinutes()).padStart(2, '0'),
628
- ss: String(d.getSeconds()).padStart(2, '0'),
629
- };
630
- let result = fmt;
631
- for (const [key, val] of Object.entries(map)) {
632
- result = result.replace(key, val);
633
- }
634
- return result;
709
+ return safeCall(() => {
710
+ const d = new Date(date);
711
+ const map = {
712
+ YYYY: String(d.getFullYear()),
713
+ MM: String(d.getMonth() + 1).padStart(2, '0'),
714
+ DD: String(d.getDate()).padStart(2, '0'),
715
+ HH: String(d.getHours()).padStart(2, '0'),
716
+ mm: String(d.getMinutes()).padStart(2, '0'),
717
+ ss: String(d.getSeconds()).padStart(2, '0'),
718
+ };
719
+ let result = fmt;
720
+ for (const [key, val] of Object.entries(map)) {
721
+ result = result.replace(key, val);
722
+ }
723
+ return result;
724
+ }, '', 'formatDate');
635
725
  }
636
726
  /**
637
727
  * 数字格式化(千分位等)
638
728
  */
639
729
  function formatNumber(num, options = {}) {
640
- const { precision, separator = ',' } = options;
641
- let str = precision !== undefined ? num.toFixed(precision) : String(num);
642
- const [intPart, decPart] = str.split('.');
643
- const formatted = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
644
- return decPart !== undefined ? `${formatted}.${decPart}` : formatted;
730
+ return safeCall(() => {
731
+ const { precision, separator = ',' } = options;
732
+ let str = precision !== undefined ? num.toFixed(precision) : String(num);
733
+ const [intPart, decPart] = str.split('.');
734
+ const formatted = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
735
+ return decPart !== undefined ? `${formatted}.${decPart}` : formatted;
736
+ }, String(num), 'formatNumber');
645
737
  }
646
738
  /**
647
739
  * 手机号格式化 (xxx xxxx xxxx)
648
740
  */
649
741
  function formatPhone(phone) {
650
- return phone.replace(/(\d{3})(\d{0,4})(\d{0,4})/, (_, a, b, c) => {
742
+ return safeCall(() => phone.replace(/(\d{3})(\d{0,4})(\d{0,4})/, (_, a, b, c) => {
651
743
  let result = a;
652
744
  if (b)
653
745
  result += ` ${b}`;
654
746
  if (c)
655
747
  result += ` ${c}`;
656
748
  return result;
657
- });
749
+ }), phone, 'formatPhone');
658
750
  }
659
751
  /**
660
752
  * 金额格式化
661
753
  */
662
754
  function formatMoney(amount, precision = 2) {
663
- return formatNumber(amount, { precision });
755
+ return safeCall(() => formatNumber(amount, { precision }), String(amount), 'formatMoney');
664
756
  }
665
757
  /**
666
758
  * 节流
@@ -671,7 +763,12 @@ function throttle(fn, delay) {
671
763
  const now = Date.now();
672
764
  if (now - last >= delay) {
673
765
  last = now;
674
- fn.apply(this, args);
766
+ try {
767
+ fn.apply(this, args);
768
+ }
769
+ catch (e) {
770
+ console.error('[h5-utils] throttle error:', (e === null || e === void 0 ? void 0 : e.message) || e);
771
+ }
675
772
  }
676
773
  };
677
774
  }
@@ -683,7 +780,14 @@ function debounce(fn, delay) {
683
780
  return function (...args) {
684
781
  if (timer)
685
782
  clearTimeout(timer);
686
- timer = setTimeout(() => fn.apply(this, args), delay);
783
+ timer = setTimeout(() => {
784
+ try {
785
+ fn.apply(this, args);
786
+ }
787
+ catch (e) {
788
+ console.error('[h5-utils] debounce error:', (e === null || e === void 0 ? void 0 : e.message) || e);
789
+ }
790
+ }, delay);
687
791
  };
688
792
  }
689
793
 
@@ -701,40 +805,41 @@ const patterns = {
701
805
  * 手机号格式校验
702
806
  */
703
807
  function isMobilePhone(str) {
704
- return patterns.mobile.test(str);
808
+ return safeCall(() => patterns.mobile.test(str), false, 'isMobilePhone');
705
809
  }
706
810
  /**
707
811
  * 邮箱校验
708
812
  */
709
813
  function isEmail(str) {
710
- return patterns.email.test(str);
814
+ return safeCall(() => patterns.email.test(str), false, 'isEmail');
711
815
  }
712
816
  /**
713
817
  * 身份证号校验(18位)
714
818
  */
715
819
  function isIdCard(str) {
716
- if (!patterns.idCard.test(str))
717
- return false;
718
- // 校验位验证
719
- const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
720
- const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
721
- let sum = 0;
722
- for (let i = 0; i < 17; i++) {
723
- sum += parseInt(str[i], 10) * weights[i];
724
- }
725
- return checkCodes[sum % 11] === str[17].toUpperCase();
820
+ return safeCall(() => {
821
+ if (!patterns.idCard.test(str))
822
+ return false;
823
+ const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
824
+ const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
825
+ let sum = 0;
826
+ for (let i = 0; i < 17; i++) {
827
+ sum += parseInt(str[i], 10) * weights[i];
828
+ }
829
+ return checkCodes[sum % 11] === str[17].toUpperCase();
830
+ }, false, 'isIdCard');
726
831
  }
727
832
  /**
728
833
  * URL 校验
729
834
  */
730
835
  function isUrl(str) {
731
- return patterns.url.test(str);
836
+ return safeCall(() => patterns.url.test(str), false, 'isUrl');
732
837
  }
733
838
  /**
734
839
  * 中文校验
735
840
  */
736
841
  function isChinese(str) {
737
- return patterns.chinese.test(str);
842
+ return safeCall(() => patterns.chinese.test(str), false, 'isChinese');
738
843
  }
739
844
 
740
845
  export { $, $$, addClass, buildUrl, clear as clearStorage, copyText, debounce, delegate, formatDate, formatMoney, formatNumber, formatPhone, getAdapter, getAllQueryParams, getBrowserType, get as getCookie, getDeviceInfo, getOS, getQueryParam, get$1 as getStorage, getStyle, hasClass, isAndroid, isChinese, isEmail, isIOS, isIdCard, isInViewport, isMobile, isMobilePhone, isUrl, isWeChat, lockScroll, off, on, once, parseUrl, readText, removeClass, remove as removeCookie, remove$1 as removeStorage, scrollToElement, scrollToTop, setAdapter, set as setCookie, set$1 as setStorage, throttle, toggleClass, unlockScroll };