sculp-js 0.1.1 → 1.0.0
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/README.md +3 -0
- package/lib/cjs/array.js +29 -23
- package/lib/cjs/async.js +3 -3
- package/lib/cjs/clipboard.js +3 -3
- package/lib/cjs/cookie.js +5 -5
- package/lib/cjs/date.js +130 -12
- package/lib/cjs/dom.js +13 -11
- package/lib/cjs/download.js +9 -9
- package/lib/cjs/easing.js +1 -1
- package/lib/cjs/file.js +5 -4
- package/lib/cjs/func.js +1 -1
- package/lib/cjs/index.js +5 -1
- package/lib/cjs/number.js +4 -4
- package/lib/cjs/object.js +11 -9
- package/lib/cjs/path.js +1 -1
- package/lib/cjs/qs.js +5 -5
- package/lib/cjs/random.js +1 -1
- package/lib/cjs/string.js +8 -8
- package/lib/cjs/type.js +11 -2
- package/lib/cjs/unique.js +1 -1
- package/lib/cjs/url.js +1 -1
- package/lib/cjs/watermark.js +8 -9
- package/lib/es/array.js +29 -23
- package/lib/es/async.js +3 -3
- package/lib/es/clipboard.js +3 -3
- package/lib/es/cookie.js +5 -5
- package/lib/es/date.js +127 -13
- package/lib/es/dom.js +13 -11
- package/lib/es/download.js +9 -9
- package/lib/es/easing.js +1 -1
- package/lib/es/file.js +5 -4
- package/lib/es/func.js +1 -1
- package/lib/es/index.js +2 -2
- package/lib/es/number.js +4 -4
- package/lib/es/object.js +11 -9
- package/lib/es/path.js +1 -1
- package/lib/es/qs.js +5 -5
- package/lib/es/random.js +1 -1
- package/lib/es/string.js +8 -8
- package/lib/es/type.js +11 -2
- package/lib/es/unique.js +1 -1
- package/lib/es/url.js +1 -1
- package/lib/es/watermark.js +8 -9
- package/lib/index.d.ts +121 -62
- package/lib/umd/index.js +229 -94
- package/package.json +3 -2
package/lib/umd/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* sculp-js
|
|
2
|
+
* sculp-js v1.0.0
|
|
3
3
|
* (c) 2023-2023 chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.sculpJs = {}, global.bezier));
|
|
11
11
|
})(this, (function (exports, bezier) { 'use strict';
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* 判断任意值的数据类型
|
|
15
|
+
* @param {unknown} any
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
13
18
|
const typeIs = (any) => Object.prototype.toString.call(any).slice(8, -1);
|
|
14
19
|
// 基本数据类型判断
|
|
15
20
|
const isString = (any) => typeof any === 'string';
|
|
@@ -23,7 +28,11 @@
|
|
|
23
28
|
// 复合数据类型判断
|
|
24
29
|
const isObject = (any) => typeIs(any) === 'Object';
|
|
25
30
|
const isArray = (any) => Array.isArray(any);
|
|
26
|
-
|
|
31
|
+
/**
|
|
32
|
+
* 判断是否为函数
|
|
33
|
+
* @param {unknown} any
|
|
34
|
+
* @returns {boolean}
|
|
35
|
+
*/
|
|
27
36
|
const isFunction = (any) => typeof any === 'function';
|
|
28
37
|
// 对象类型判断
|
|
29
38
|
const isNaN = (any) => Number.isNaN(any);
|
|
@@ -52,20 +61,22 @@
|
|
|
52
61
|
* @param {string} key
|
|
53
62
|
* @returns {boolean}
|
|
54
63
|
*/
|
|
55
|
-
|
|
64
|
+
function objectHas(obj, key) {
|
|
65
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
66
|
+
}
|
|
56
67
|
/**
|
|
57
68
|
* 遍历对象,返回 false 中断遍历
|
|
58
69
|
* @param {O} obj
|
|
59
70
|
* @param {(val: O[keyof O], key: keyof O) => (boolean | void)} iterator
|
|
60
71
|
*/
|
|
61
|
-
|
|
72
|
+
function objectEach(obj, iterator) {
|
|
62
73
|
for (const key in obj) {
|
|
63
74
|
if (!objectHas(obj, key))
|
|
64
75
|
continue;
|
|
65
76
|
if (iterator(obj[key], key) === false)
|
|
66
77
|
break;
|
|
67
78
|
}
|
|
68
|
-
}
|
|
79
|
+
}
|
|
69
80
|
/**
|
|
70
81
|
* 异步遍历对象,返回 false 中断遍历
|
|
71
82
|
* @param {O} obj
|
|
@@ -171,7 +182,7 @@
|
|
|
171
182
|
* @param {ObjectAssignItem | undefined} targets
|
|
172
183
|
* @returns {R}
|
|
173
184
|
*/
|
|
174
|
-
|
|
185
|
+
function objectAssign(source, ...targets) {
|
|
175
186
|
const map = new Map();
|
|
176
187
|
for (let i = 0; i < targets.length; i++) {
|
|
177
188
|
const target = targets[i];
|
|
@@ -181,7 +192,7 @@
|
|
|
181
192
|
}
|
|
182
193
|
map.clear();
|
|
183
194
|
return source;
|
|
184
|
-
}
|
|
195
|
+
}
|
|
185
196
|
/**
|
|
186
197
|
* 对象填充
|
|
187
198
|
* @param {Partial<R>} source
|
|
@@ -189,7 +200,7 @@
|
|
|
189
200
|
* @param {(s: Partial<R>, t: Partial<R>, key: keyof R) => boolean} fillable
|
|
190
201
|
* @returns {R}
|
|
191
202
|
*/
|
|
192
|
-
|
|
203
|
+
function objectFill(source, target, fillable) {
|
|
193
204
|
const _fillable = fillable || ((source, target, key) => source[key] === undefined);
|
|
194
205
|
objectEach(target, (val, key) => {
|
|
195
206
|
if (_fillable(source, target, key)) {
|
|
@@ -197,7 +208,7 @@
|
|
|
197
208
|
}
|
|
198
209
|
});
|
|
199
210
|
return source;
|
|
200
|
-
}
|
|
211
|
+
}
|
|
201
212
|
function objectGet(obj, path, strict = false) {
|
|
202
213
|
path = path.replace(/\[(\w+)\]/g, '.$1');
|
|
203
214
|
path = path.replace(/^\./, '');
|
|
@@ -230,7 +241,7 @@
|
|
|
230
241
|
* 深拷贝堪称完全体 即:任何类型的数据都会被深拷贝
|
|
231
242
|
* @param {AnyObject | AnyArray} obj
|
|
232
243
|
* @param {WeakMap} map
|
|
233
|
-
* @
|
|
244
|
+
* @returns {AnyObject | AnyArray}
|
|
234
245
|
*/
|
|
235
246
|
function cloneDeep(obj, map = new WeakMap()) {
|
|
236
247
|
if (obj instanceof Date)
|
|
@@ -252,10 +263,11 @@
|
|
|
252
263
|
|
|
253
264
|
/**
|
|
254
265
|
* 判断一个对象是否为类数组
|
|
266
|
+
*
|
|
255
267
|
* @param any
|
|
256
268
|
* @returns {boolean}
|
|
257
269
|
*/
|
|
258
|
-
|
|
270
|
+
function arrayLike(any) {
|
|
259
271
|
if (isArray(any))
|
|
260
272
|
return true;
|
|
261
273
|
if (isString(any))
|
|
@@ -263,14 +275,16 @@
|
|
|
263
275
|
if (!isObject(any))
|
|
264
276
|
return false;
|
|
265
277
|
return objectHas(any, 'length');
|
|
266
|
-
}
|
|
278
|
+
}
|
|
267
279
|
/**
|
|
268
280
|
* 遍历数组,返回 false 中断遍历
|
|
281
|
+
*
|
|
269
282
|
* @param {ArrayLike<V>} array
|
|
270
283
|
* @param {(val: V, idx: number) => any} iterator
|
|
271
284
|
* @param reverse {boolean} 是否倒序
|
|
285
|
+
* @returns {*}
|
|
272
286
|
*/
|
|
273
|
-
|
|
287
|
+
function arrayEach(array, iterator, reverse = false) {
|
|
274
288
|
if (reverse) {
|
|
275
289
|
for (let idx = array.length - 1; idx >= 0; idx--) {
|
|
276
290
|
const val = array[idx];
|
|
@@ -285,12 +299,12 @@
|
|
|
285
299
|
break;
|
|
286
300
|
}
|
|
287
301
|
}
|
|
288
|
-
}
|
|
302
|
+
}
|
|
289
303
|
/**
|
|
290
304
|
* 异步遍历数组,返回 false 中断遍历
|
|
291
|
-
* @param {ArrayLike<V>} array
|
|
292
|
-
* @param {(val: V, idx: number) => Promise<any>} iterator
|
|
293
|
-
* @param {boolean} reverse
|
|
305
|
+
* @param {ArrayLike<V>} array 数组
|
|
306
|
+
* @param {(val: V, idx: number) => Promise<any>} iterator 支持Promise类型的回调函数
|
|
307
|
+
* @param {boolean} reverse 是否反向遍历
|
|
294
308
|
*/
|
|
295
309
|
async function arrayEachAsync(array, iterator, reverse = false) {
|
|
296
310
|
if (reverse) {
|
|
@@ -313,15 +327,16 @@
|
|
|
313
327
|
* @param {AnyArray} array
|
|
314
328
|
* @param {number} start
|
|
315
329
|
* @param {number} to
|
|
330
|
+
* @returns {*}
|
|
316
331
|
*/
|
|
317
|
-
|
|
332
|
+
function arrayInsertBefore(array, start, to) {
|
|
318
333
|
if (start === to || start + 1 === to)
|
|
319
334
|
return;
|
|
320
335
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
321
336
|
const [source] = array.splice(start, 1);
|
|
322
337
|
const insertIndex = to < start ? to : to - 1;
|
|
323
338
|
array.splice(insertIndex, 0, source);
|
|
324
|
-
}
|
|
339
|
+
}
|
|
325
340
|
/**
|
|
326
341
|
* 数组删除指定项目
|
|
327
342
|
* @param {V[]} array
|
|
@@ -342,17 +357,18 @@
|
|
|
342
357
|
}
|
|
343
358
|
/**
|
|
344
359
|
* 自定义深度优先遍历函数(支持continue和break操作)
|
|
345
|
-
* @param {
|
|
346
|
-
* @param {
|
|
347
|
-
* @param {
|
|
348
|
-
* @param {boolean} isReverse
|
|
360
|
+
* @param {ArrayLike<V>} tree 树形数据
|
|
361
|
+
* @param {Function} iterator 迭代函数
|
|
362
|
+
* @param {string} children 定制子元素的key
|
|
363
|
+
* @param {boolean} isReverse 是否反向遍历
|
|
364
|
+
* @returns {*}
|
|
349
365
|
*/
|
|
350
|
-
|
|
366
|
+
function deepTraversal(tree, iterator, children = 'children', isReverse = false) {
|
|
351
367
|
let level = 0;
|
|
352
368
|
const walk = (arr, parent) => {
|
|
353
369
|
if (isReverse) {
|
|
354
370
|
for (let i = arr.length - 1; i >= 0; i--) {
|
|
355
|
-
const re = iterator(arr[i], i,
|
|
371
|
+
const re = iterator(arr[i], i, tree, parent, level);
|
|
356
372
|
if (re === 'break') {
|
|
357
373
|
break;
|
|
358
374
|
}
|
|
@@ -369,7 +385,7 @@
|
|
|
369
385
|
}
|
|
370
386
|
else {
|
|
371
387
|
for (let i = 0; i < arr.length; i++) {
|
|
372
|
-
const re = iterator(arr[i], i,
|
|
388
|
+
const re = iterator(arr[i], i, tree, parent, level);
|
|
373
389
|
if (re === 'break') {
|
|
374
390
|
break;
|
|
375
391
|
}
|
|
@@ -385,14 +401,15 @@
|
|
|
385
401
|
}
|
|
386
402
|
}
|
|
387
403
|
};
|
|
388
|
-
walk(
|
|
389
|
-
}
|
|
404
|
+
walk(tree, null);
|
|
405
|
+
}
|
|
390
406
|
/**
|
|
391
407
|
* 在树中找到 id 为某个值的节点,并返回上游的所有父级节点
|
|
392
|
-
*
|
|
393
|
-
* @param {
|
|
394
|
-
* @param {
|
|
395
|
-
* @
|
|
408
|
+
*
|
|
409
|
+
* @param {ArrayLike<T>} tree - 树形数据
|
|
410
|
+
* @param {IdLike} nodeId - 元素ID
|
|
411
|
+
* @param {ITreeConf} config - 迭代配置项
|
|
412
|
+
* @returns {[IdLike[], ITreeItem<V>[]]} - 由parentId...childId, parentObject-childObject组成的二维数组
|
|
396
413
|
*/
|
|
397
414
|
function getTreeIds(tree, nodeId, config) {
|
|
398
415
|
const { children = 'children', id = 'id' } = config || {};
|
|
@@ -454,24 +471,24 @@
|
|
|
454
471
|
* @param {boolean} [bigger] 是否大写第一个字母
|
|
455
472
|
* @returns {string}
|
|
456
473
|
*/
|
|
457
|
-
|
|
474
|
+
function stringCamelCase(string, bigger) {
|
|
458
475
|
let string2 = string;
|
|
459
476
|
if (bigger) {
|
|
460
477
|
string2 = string.replace(/^./, origin => origin.toUpperCase());
|
|
461
478
|
}
|
|
462
479
|
const HUMP_RE = /[\s_-](.)/g;
|
|
463
480
|
return string2.replace(HUMP_RE, (orign, char) => char.toUpperCase());
|
|
464
|
-
}
|
|
481
|
+
}
|
|
465
482
|
/**
|
|
466
483
|
* 将字符串转换为连字格式
|
|
467
484
|
* @param {string} string
|
|
468
485
|
* @param {string} [separator] 分隔符,默认是"-"(短横线)
|
|
469
486
|
* @returns {string}
|
|
470
487
|
*/
|
|
471
|
-
|
|
488
|
+
function stringKebabCase(string, separator = '-') {
|
|
472
489
|
const string2 = string.replace(/^./, origin => origin.toLowerCase());
|
|
473
490
|
return string2.replace(/[A-Z]/g, origin => `${separator}${origin.toLowerCase()}`);
|
|
474
|
-
}
|
|
491
|
+
}
|
|
475
492
|
const STRING_ARABIC_NUMERALS = '0123456789';
|
|
476
493
|
const STRING_LOWERCASE_ALPHA = 'abcdefghijklmnopqrstuvwxyz';
|
|
477
494
|
const STRING_UPPERCASE_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
@@ -487,7 +504,7 @@
|
|
|
487
504
|
* @param args
|
|
488
505
|
* @returns {string}
|
|
489
506
|
*/
|
|
490
|
-
|
|
507
|
+
function stringFormat(string, ...args) {
|
|
491
508
|
let index = 0;
|
|
492
509
|
const result = string.replace(placeholderRE, (origin) => {
|
|
493
510
|
const arg = args[index++];
|
|
@@ -505,7 +522,7 @@
|
|
|
505
522
|
}
|
|
506
523
|
});
|
|
507
524
|
return [result, ...args.splice(index).map(String)].join(' ');
|
|
508
|
-
}
|
|
525
|
+
}
|
|
509
526
|
const ev = (expression, data) => {
|
|
510
527
|
try {
|
|
511
528
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval,@typescript-eslint/no-unsafe-return
|
|
@@ -569,7 +586,7 @@
|
|
|
569
586
|
* @param {string} str 目标字符串
|
|
570
587
|
* @param {number} fontSize 字符串字体大小
|
|
571
588
|
* @param {boolean} isRemoveDom 计算后是否移除中间dom元素
|
|
572
|
-
* @
|
|
589
|
+
* @returns {*}
|
|
573
590
|
*/
|
|
574
591
|
function getStrWidthPx(str, fontSize = 14, isRemoveDom = false) {
|
|
575
592
|
let strWidth = 0;
|
|
@@ -601,11 +618,11 @@
|
|
|
601
618
|
* @param {string} className
|
|
602
619
|
* @returns {boolean}
|
|
603
620
|
*/
|
|
604
|
-
|
|
621
|
+
function hasClass(el, className) {
|
|
605
622
|
if (className.indexOf(' ') !== -1)
|
|
606
623
|
throw new Error('className should not contain space.');
|
|
607
624
|
return el.classList.contains(className);
|
|
608
|
-
}
|
|
625
|
+
}
|
|
609
626
|
const eachClassName = (classNames, func) => {
|
|
610
627
|
const classNameList = classNames.split(/\s+/g);
|
|
611
628
|
classNameList.forEach(func);
|
|
@@ -615,17 +632,17 @@
|
|
|
615
632
|
* @param {HTMLElement} el
|
|
616
633
|
* @param {string} classNames
|
|
617
634
|
*/
|
|
618
|
-
|
|
635
|
+
function addClass(el, classNames) {
|
|
619
636
|
eachClassName(classNames, className => el.classList.add(className));
|
|
620
|
-
}
|
|
637
|
+
}
|
|
621
638
|
/**
|
|
622
639
|
* 给元素移除样式名
|
|
623
640
|
* @param {HTMLElement} el
|
|
624
641
|
* @param {string} classNames
|
|
625
642
|
*/
|
|
626
|
-
|
|
643
|
+
function removeClass(el, classNames) {
|
|
627
644
|
eachClassName(classNames, className => el.classList.remove(className));
|
|
628
|
-
}
|
|
645
|
+
}
|
|
629
646
|
/**
|
|
630
647
|
* 设置元素样式
|
|
631
648
|
* @param {HTMLElement} el
|
|
@@ -644,12 +661,14 @@
|
|
|
644
661
|
};
|
|
645
662
|
/**
|
|
646
663
|
* 获取元素样式
|
|
647
|
-
* @param {HTMLElement} el
|
|
664
|
+
* @param {HTMLElement} el 元素
|
|
648
665
|
* @param {string} key
|
|
649
666
|
* @returns {string}
|
|
650
667
|
*/
|
|
651
|
-
|
|
652
|
-
|
|
668
|
+
function getStyle(el, key) {
|
|
669
|
+
return getComputedStyle(el).getPropertyValue(key);
|
|
670
|
+
}
|
|
671
|
+
function smoothScroll(options) {
|
|
653
672
|
return new Promise(resolve => {
|
|
654
673
|
const defaults = {
|
|
655
674
|
el: document,
|
|
@@ -729,7 +748,7 @@
|
|
|
729
748
|
* @param {HTMLElement} el
|
|
730
749
|
* @param {string} property
|
|
731
750
|
* @param {boolean} reNumber
|
|
732
|
-
* @
|
|
751
|
+
* @returns {string|number}
|
|
733
752
|
*/
|
|
734
753
|
function getComputedCssVal(el, property, reNumber = true) {
|
|
735
754
|
const originVal = getComputedStyle(el).getPropertyValue(property) ?? '';
|
|
@@ -748,7 +767,7 @@
|
|
|
748
767
|
* 复制文本
|
|
749
768
|
* @param {string} text
|
|
750
769
|
*/
|
|
751
|
-
|
|
770
|
+
function copyText(text) {
|
|
752
771
|
textEl.value = text;
|
|
753
772
|
textEl.focus({ preventScroll: true });
|
|
754
773
|
textEl.select();
|
|
@@ -759,14 +778,14 @@
|
|
|
759
778
|
catch (err) {
|
|
760
779
|
// ignore
|
|
761
780
|
}
|
|
762
|
-
}
|
|
781
|
+
}
|
|
763
782
|
|
|
764
783
|
/**
|
|
765
784
|
* 获取cookie
|
|
766
785
|
* @param {string} name
|
|
767
786
|
* @returns {string}
|
|
768
787
|
*/
|
|
769
|
-
|
|
788
|
+
function cookieGet(name) {
|
|
770
789
|
const { cookie } = document;
|
|
771
790
|
if (!cookie)
|
|
772
791
|
return '';
|
|
@@ -778,14 +797,14 @@
|
|
|
778
797
|
return decodeURIComponent(val);
|
|
779
798
|
}
|
|
780
799
|
return '';
|
|
781
|
-
}
|
|
800
|
+
}
|
|
782
801
|
/**
|
|
783
802
|
* 设置 cookie
|
|
784
803
|
* @param {string} name
|
|
785
804
|
* @param {string} value
|
|
786
805
|
* @param {number | Date} [maxAge]
|
|
787
806
|
*/
|
|
788
|
-
|
|
807
|
+
function cookieSet(name, value, maxAge) {
|
|
789
808
|
const metas = [];
|
|
790
809
|
const EXPIRES = 'expires';
|
|
791
810
|
metas.push([name, encodeURIComponent(value)]);
|
|
@@ -804,13 +823,66 @@
|
|
|
804
823
|
return `${key}=${val}`;
|
|
805
824
|
})
|
|
806
825
|
.join(';');
|
|
807
|
-
}
|
|
826
|
+
}
|
|
808
827
|
/**
|
|
809
828
|
* 删除单个 cookie
|
|
810
829
|
* @param name cookie 名称
|
|
811
830
|
*/
|
|
812
831
|
const cookieDel = (name) => cookieSet(name, '', -1);
|
|
813
832
|
|
|
833
|
+
const isValidDate = (any) => isDate(any) && !isNaN(any.getTime());
|
|
834
|
+
/* istanbul ignore next */
|
|
835
|
+
const guessDateSeparator = (value) => {
|
|
836
|
+
if (!isString(value))
|
|
837
|
+
return;
|
|
838
|
+
const value2 = value.replace(/-/g, '/');
|
|
839
|
+
return new Date(value2);
|
|
840
|
+
};
|
|
841
|
+
/* istanbul ignore next */
|
|
842
|
+
const guessDateTimezone = (value) => {
|
|
843
|
+
if (!isString(value))
|
|
844
|
+
return;
|
|
845
|
+
const re = /([+-])(\d\d)(\d\d)$/;
|
|
846
|
+
const matches = re.exec(value);
|
|
847
|
+
if (!matches)
|
|
848
|
+
return;
|
|
849
|
+
const value2 = value.replace(re, 'Z');
|
|
850
|
+
const d = new Date(value2);
|
|
851
|
+
if (!isValidDate(d))
|
|
852
|
+
return;
|
|
853
|
+
const [, flag, hours, minutes] = matches;
|
|
854
|
+
const hours2 = parseInt(hours, 10);
|
|
855
|
+
const minutes2 = parseInt(minutes, 10);
|
|
856
|
+
const offset = (a, b) => (flag === '+' ? a - b : a + b);
|
|
857
|
+
d.setHours(offset(d.getHours(), hours2));
|
|
858
|
+
d.setMinutes(offset(d.getMinutes(), minutes2));
|
|
859
|
+
return d;
|
|
860
|
+
};
|
|
861
|
+
/**
|
|
862
|
+
* 解析为Date对象
|
|
863
|
+
* @param {DateValue} value - 可以是数值、字符串或 Date 对象
|
|
864
|
+
* @returns {Date} - 转换后的目标Date
|
|
865
|
+
*/
|
|
866
|
+
function dateParse(value) {
|
|
867
|
+
const d1 = new Date(value);
|
|
868
|
+
if (isValidDate(d1))
|
|
869
|
+
return d1;
|
|
870
|
+
// safari 浏览器的日期解析有问题
|
|
871
|
+
// new Date('2020-06-26 18:06:15') 返回值是一个非法日期对象
|
|
872
|
+
/* istanbul ignore next */
|
|
873
|
+
const d2 = guessDateSeparator(value);
|
|
874
|
+
/* istanbul ignore next */
|
|
875
|
+
if (isValidDate(d2))
|
|
876
|
+
return d2;
|
|
877
|
+
// safari 浏览器的日期解析有问题
|
|
878
|
+
// new Date('2020-06-26T18:06:15.000+0800') 返回值是一个非法日期对象
|
|
879
|
+
/* istanbul ignore next */
|
|
880
|
+
const d3 = guessDateTimezone(value);
|
|
881
|
+
/* istanbul ignore next */
|
|
882
|
+
if (isValidDate(d3))
|
|
883
|
+
return d3;
|
|
884
|
+
throw new SyntaxError(`${value.toString()} 不是一个合法的日期描述`);
|
|
885
|
+
}
|
|
814
886
|
/**
|
|
815
887
|
* 格式化为日期对象(带自定义格式化模板)
|
|
816
888
|
* @param {DateValue} value 可以是数值、字符串或 Date 对象
|
|
@@ -825,10 +897,69 @@
|
|
|
825
897
|
* - mm:分
|
|
826
898
|
* - ss:秒
|
|
827
899
|
* - SSS:毫秒
|
|
828
|
-
* - ww: 周
|
|
829
900
|
* @returns {string}
|
|
830
901
|
*/
|
|
831
|
-
const
|
|
902
|
+
// export const dateStringify = (value: DateValue, format = 'YYYY-MM-DD HH:mm:ss'): string => {
|
|
903
|
+
// const date = dateParse(value);
|
|
904
|
+
// let fmt = format;
|
|
905
|
+
// let ret;
|
|
906
|
+
// const opt: DateObj = {
|
|
907
|
+
// 'Y+': `${date.getFullYear()}`, // 年
|
|
908
|
+
// 'y+': `${date.getFullYear()}`, // 年
|
|
909
|
+
// 'M+': `${date.getMonth() + 1}`, // 月
|
|
910
|
+
// 'D+': `${date.getDate()}`, // 日
|
|
911
|
+
// 'd+': `${date.getDate()}`, // 日
|
|
912
|
+
// 'H+': `${date.getHours()}`, // 时
|
|
913
|
+
// 'm+': `${date.getMinutes()}`, // 分
|
|
914
|
+
// 's+': `${date.getSeconds()}`, // 秒
|
|
915
|
+
// 'S+': `${date.getMilliseconds()}` // 豪秒
|
|
916
|
+
// };
|
|
917
|
+
// for (const k in opt) {
|
|
918
|
+
// ret = new RegExp(`(${k})`).exec(fmt);
|
|
919
|
+
// if (ret) {
|
|
920
|
+
// fmt = fmt.replace(ret[1], ret[1].length === 1 ? opt[k] : opt[k].padStart(ret[1].length, '0'));
|
|
921
|
+
// }
|
|
922
|
+
// }
|
|
923
|
+
// return fmt;
|
|
924
|
+
// };
|
|
925
|
+
/**
|
|
926
|
+
* 将日期转换为一天的开始时间,即0点0分0秒0毫秒
|
|
927
|
+
* @param {DateValue} value
|
|
928
|
+
* @returns {Date}
|
|
929
|
+
*/
|
|
930
|
+
function dateToStart(value) {
|
|
931
|
+
const d = dateParse(value);
|
|
932
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0);
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* 将日期转换为一天的结束时间,即23点59分59秒999毫秒
|
|
936
|
+
* @param {DateValue} value
|
|
937
|
+
* @returns {Date}
|
|
938
|
+
*/
|
|
939
|
+
function dateToEnd(value) {
|
|
940
|
+
const d = dateToStart(value);
|
|
941
|
+
d.setDate(d.getDate() + 1);
|
|
942
|
+
return dateParse(d.getTime() - 1);
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* 格式化为日期对象(带自定义格式化模板)
|
|
946
|
+
* @param {Date} value - 可以是数值、字符串或 Date 对象
|
|
947
|
+
* @param {string} [format] - 模板,默认是 YYYY-MM-DD HH:mm:ss,模板字符:
|
|
948
|
+
* - YYYY:年
|
|
949
|
+
* - yyyy: 年
|
|
950
|
+
* - MM:月
|
|
951
|
+
* - DD:日
|
|
952
|
+
* - dd: 日
|
|
953
|
+
* - HH:时(24 小时制)
|
|
954
|
+
* - hh:时(12 小时制)
|
|
955
|
+
* - mm:分
|
|
956
|
+
* - ss:秒
|
|
957
|
+
* - SSS:毫秒
|
|
958
|
+
* - ww: 周
|
|
959
|
+
* @returns {string} 格式化后的日期字符串
|
|
960
|
+
*/
|
|
961
|
+
function formatDate(value, format = 'YYYY-MM-DD HH:mm:ss') {
|
|
962
|
+
const date = dateParse(value);
|
|
832
963
|
let fmt = format;
|
|
833
964
|
let ret;
|
|
834
965
|
const opt = {
|
|
@@ -851,13 +982,13 @@
|
|
|
851
982
|
}
|
|
852
983
|
}
|
|
853
984
|
return fmt;
|
|
854
|
-
}
|
|
985
|
+
}
|
|
855
986
|
/**
|
|
856
987
|
* 计算向前或向后N天的具体日期
|
|
857
|
-
* @param {string} strDate 参考日期
|
|
858
|
-
* @param {number} n 正数:向后推算;负数:向前推算
|
|
859
|
-
* @param {string} sep 日期格式的分隔符
|
|
860
|
-
* @
|
|
988
|
+
* @param {string} strDate - 参考日期
|
|
989
|
+
* @param {number} n - 正数:向后推算;负数:向前推算
|
|
990
|
+
* @param {string} sep - 日期格式的分隔符
|
|
991
|
+
* @returns {string} 计算后的目标日期
|
|
861
992
|
*/
|
|
862
993
|
function calculateDate(strDate, n, sep = '-') {
|
|
863
994
|
//strDate 为字符串日期 如:'2019-01-01' n为你要传入的参数,当前为0,前一天为-1,后一天为1
|
|
@@ -875,10 +1006,10 @@
|
|
|
875
1006
|
}
|
|
876
1007
|
/**
|
|
877
1008
|
* 计算向前或向后N天的具体时间日期
|
|
878
|
-
* @param {number} n 正数:向后推算;负数:向前推算
|
|
879
|
-
* @param {string} dateSep 日期分隔符
|
|
880
|
-
* @param {string} timeSep 时间分隔符
|
|
881
|
-
* @
|
|
1009
|
+
* @param {number} n - 正数:向后推算;负数:向前推算
|
|
1010
|
+
* @param {string} dateSep - 日期分隔符
|
|
1011
|
+
* @param {string} timeSep - 时间分隔符
|
|
1012
|
+
* @returns {string} 转换后的目标日期时间
|
|
882
1013
|
*/
|
|
883
1014
|
function calculateDateTime(n, dateSep = '-', timeSep = ':') {
|
|
884
1015
|
const date = new Date();
|
|
@@ -975,7 +1106,7 @@
|
|
|
975
1106
|
* @param {string} queryString
|
|
976
1107
|
* @returns {Params}
|
|
977
1108
|
*/
|
|
978
|
-
|
|
1109
|
+
function qsParse(queryString) {
|
|
979
1110
|
const params = new URLSearchParams(queryString);
|
|
980
1111
|
const result = {};
|
|
981
1112
|
for (const [key, val] of params.entries()) {
|
|
@@ -989,7 +1120,7 @@
|
|
|
989
1120
|
result[key] = params.getAll(key);
|
|
990
1121
|
}
|
|
991
1122
|
return result;
|
|
992
|
-
}
|
|
1123
|
+
}
|
|
993
1124
|
const defaultReplacer = (val) => {
|
|
994
1125
|
if (isString(val))
|
|
995
1126
|
return val;
|
|
@@ -1007,7 +1138,7 @@
|
|
|
1007
1138
|
* @param {Replacer} replacer
|
|
1008
1139
|
* @returns {string}
|
|
1009
1140
|
*/
|
|
1010
|
-
|
|
1141
|
+
function qsStringify(query, replacer = defaultReplacer) {
|
|
1011
1142
|
const params = new URLSearchParams();
|
|
1012
1143
|
objectEach(query, (val, key) => {
|
|
1013
1144
|
if (isArray(val)) {
|
|
@@ -1026,7 +1157,7 @@
|
|
|
1026
1157
|
}
|
|
1027
1158
|
});
|
|
1028
1159
|
return params.toString();
|
|
1029
|
-
}
|
|
1160
|
+
}
|
|
1030
1161
|
|
|
1031
1162
|
const anchorEl = document.createElement('a');
|
|
1032
1163
|
/**
|
|
@@ -1102,15 +1233,15 @@
|
|
|
1102
1233
|
* @param {string} url
|
|
1103
1234
|
* @param {LooseParams} params
|
|
1104
1235
|
*/
|
|
1105
|
-
|
|
1236
|
+
function downloadURL(url, params) {
|
|
1106
1237
|
window.open(params ? urlSetParams(url, params) : url);
|
|
1107
|
-
}
|
|
1238
|
+
}
|
|
1108
1239
|
/**
|
|
1109
1240
|
* 通过 A 链接的方式下载
|
|
1110
1241
|
* @param {string} href
|
|
1111
1242
|
* @param {string} filename
|
|
1112
1243
|
*/
|
|
1113
|
-
|
|
1244
|
+
function downloadHref(href, filename) {
|
|
1114
1245
|
const eleLink = document.createElement('a');
|
|
1115
1246
|
eleLink.download = filename;
|
|
1116
1247
|
eleLink.style.display = 'none';
|
|
@@ -1118,17 +1249,17 @@
|
|
|
1118
1249
|
document.body.appendChild(eleLink);
|
|
1119
1250
|
eleLink.click();
|
|
1120
1251
|
setTimeout(() => document.body.removeChild(eleLink));
|
|
1121
|
-
}
|
|
1252
|
+
}
|
|
1122
1253
|
/**
|
|
1123
1254
|
* 将大文件对象通过 A 链接的方式下载
|
|
1124
1255
|
* @param {Blob} blob
|
|
1125
1256
|
* @param {string} filename
|
|
1126
1257
|
*/
|
|
1127
|
-
|
|
1258
|
+
function downloadBlob(blob, filename) {
|
|
1128
1259
|
const objURL = URL.createObjectURL(blob);
|
|
1129
1260
|
downloadHref(objURL, filename);
|
|
1130
1261
|
setTimeout(() => URL.revokeObjectURL(objURL));
|
|
1131
|
-
}
|
|
1262
|
+
}
|
|
1132
1263
|
/**
|
|
1133
1264
|
* 将指定数据格式通过 A 链接的方式下载
|
|
1134
1265
|
* @param {AnyObject | AnyObject[]} data
|
|
@@ -1136,7 +1267,7 @@
|
|
|
1136
1267
|
* @param {string} filename
|
|
1137
1268
|
* @param {string[]} [headers]
|
|
1138
1269
|
*/
|
|
1139
|
-
|
|
1270
|
+
function downloadData(data, fileType, filename, headers) {
|
|
1140
1271
|
filename = filename.replace(`.${fileType}`, '') + `.${fileType}`;
|
|
1141
1272
|
if (fileType === 'json') {
|
|
1142
1273
|
const blob = new Blob([JSON.stringify(data, null, 4)]);
|
|
@@ -1163,14 +1294,14 @@
|
|
|
1163
1294
|
const href = 'data:' + MIMETypes[fileType] + ';charset=utf-8,\ufeff' + encodeURIComponent(headerStr + bodyStr);
|
|
1164
1295
|
downloadHref(href, filename);
|
|
1165
1296
|
}
|
|
1166
|
-
}
|
|
1297
|
+
}
|
|
1167
1298
|
|
|
1168
1299
|
/**
|
|
1169
1300
|
* 等待一段时间
|
|
1170
1301
|
* @param {number} timeout 等待时间,单位毫秒
|
|
1171
1302
|
* @returns {Promise<void>}
|
|
1172
1303
|
*/
|
|
1173
|
-
|
|
1304
|
+
function wait(timeout = 1) {
|
|
1174
1305
|
return new Promise(resolve => setTimeout(resolve, timeout));
|
|
1175
1306
|
}
|
|
1176
1307
|
/**
|
|
@@ -1182,7 +1313,7 @@
|
|
|
1182
1313
|
* @param {number} concurrency 并发数量,默认无限
|
|
1183
1314
|
* @returns {Promise<R[]>}
|
|
1184
1315
|
*/
|
|
1185
|
-
|
|
1316
|
+
function asyncMap(list, mapper, concurrency = Infinity) {
|
|
1186
1317
|
return new Promise((resolve, reject) => {
|
|
1187
1318
|
const iterator = list[Symbol.iterator]();
|
|
1188
1319
|
const limit = Math.min(list.length, concurrency);
|
|
@@ -1220,10 +1351,11 @@
|
|
|
1220
1351
|
|
|
1221
1352
|
/**
|
|
1222
1353
|
* 选择本地文件
|
|
1223
|
-
* @param {
|
|
1224
|
-
* @
|
|
1354
|
+
* @param {string} accept 上传的文件类型,用于过滤
|
|
1355
|
+
* @param {Function} changeCb 选择文件回调
|
|
1356
|
+
* @returns {HTMLInputElement}
|
|
1225
1357
|
*/
|
|
1226
|
-
function chooseLocalFile(
|
|
1358
|
+
function chooseLocalFile(accept, changeCb) {
|
|
1227
1359
|
const inputObj = document.createElement('input');
|
|
1228
1360
|
inputObj.setAttribute('id', String(Date.now()));
|
|
1229
1361
|
inputObj.setAttribute('type', 'file');
|
|
@@ -1246,17 +1378,18 @@
|
|
|
1246
1378
|
* @desc 网页加水印的工具类
|
|
1247
1379
|
*/
|
|
1248
1380
|
/**
|
|
1249
|
-
* canvas 实现
|
|
1381
|
+
* canvas 实现 水印, 具备防删除功能
|
|
1250
1382
|
* @param {ICanvasWM} canvasWM
|
|
1383
|
+
* @example genCanvasWM({ content: 'QQMusicFE' })
|
|
1251
1384
|
*/
|
|
1252
|
-
|
|
1385
|
+
function genCanvasWM(canvasWM) {
|
|
1253
1386
|
const { container = document.body, width = '300px', height = '200px', textAlign = 'center', textBaseline = 'middle', font = '20px PingFangSC-Medium,PingFang SC',
|
|
1254
1387
|
// fontWeight = 500,
|
|
1255
1388
|
fillStyle = 'rgba(189, 177, 167, .3)', content = '请勿外传', rotate = 30, zIndex = 2147483647 } = canvasWM;
|
|
1256
1389
|
// 仅限主页面添加水印
|
|
1257
|
-
if (!location.pathname.includes('/home')) {
|
|
1258
|
-
|
|
1259
|
-
}
|
|
1390
|
+
// if (!location.pathname.includes('/home')) {
|
|
1391
|
+
// return;
|
|
1392
|
+
// }
|
|
1260
1393
|
const args = canvasWM;
|
|
1261
1394
|
const canvas = document.createElement('canvas');
|
|
1262
1395
|
canvas.setAttribute('width', width);
|
|
@@ -1317,9 +1450,7 @@
|
|
|
1317
1450
|
});
|
|
1318
1451
|
mo.observe(container, { attributes: true, subtree: true, childList: true });
|
|
1319
1452
|
}
|
|
1320
|
-
}
|
|
1321
|
-
// 调用
|
|
1322
|
-
// __canvasWM({ content: 'QQMusicFE' })
|
|
1453
|
+
}
|
|
1323
1454
|
|
|
1324
1455
|
/**
|
|
1325
1456
|
* 防抖函数
|
|
@@ -1537,7 +1668,7 @@
|
|
|
1537
1668
|
* @param {string} [hexPool] 进制池,默认 62 进制
|
|
1538
1669
|
* @returns {string}
|
|
1539
1670
|
*/
|
|
1540
|
-
|
|
1671
|
+
function numberToHex(decimal, hexPool = HEX_POOL) {
|
|
1541
1672
|
if (hexPool.length < 2)
|
|
1542
1673
|
throw new Error('进制池长度不能少于 2');
|
|
1543
1674
|
if (!supportBigInt) {
|
|
@@ -1559,7 +1690,7 @@
|
|
|
1559
1690
|
};
|
|
1560
1691
|
execute();
|
|
1561
1692
|
return ret.join('');
|
|
1562
|
-
}
|
|
1693
|
+
}
|
|
1563
1694
|
/**
|
|
1564
1695
|
* 缩写
|
|
1565
1696
|
* @param {number | string} num
|
|
@@ -1586,7 +1717,7 @@
|
|
|
1586
1717
|
* 将数字格式化成千位分隔符显示的字符串
|
|
1587
1718
|
* @param {number} val 数字
|
|
1588
1719
|
* @param {'int' | 'float'} type 展示分段显示的类型 int:整型 | float:浮点型
|
|
1589
|
-
* @
|
|
1720
|
+
* @returns {string}
|
|
1590
1721
|
*/
|
|
1591
1722
|
function formatNumber(val, type = 'int') {
|
|
1592
1723
|
return type === 'int' ? parseInt(String(val)).toLocaleString() : Number(val).toLocaleString('en-US');
|
|
@@ -1681,6 +1812,9 @@
|
|
|
1681
1812
|
exports.cookieGet = cookieGet;
|
|
1682
1813
|
exports.cookieSet = cookieSet;
|
|
1683
1814
|
exports.copyText = copyText;
|
|
1815
|
+
exports.dateParse = dateParse;
|
|
1816
|
+
exports.dateToEnd = dateToEnd;
|
|
1817
|
+
exports.dateToStart = dateToStart;
|
|
1684
1818
|
exports.debounce = debounce;
|
|
1685
1819
|
exports.deepTraversal = deepTraversal;
|
|
1686
1820
|
exports.downloadBlob = downloadBlob;
|
|
@@ -1713,6 +1847,7 @@
|
|
|
1713
1847
|
exports.isString = isString;
|
|
1714
1848
|
exports.isSymbol = isSymbol;
|
|
1715
1849
|
exports.isUndefined = isUndefined;
|
|
1850
|
+
exports.isValidDate = isValidDate;
|
|
1716
1851
|
exports.numberAbbr = numberAbbr;
|
|
1717
1852
|
exports.numberToHex = numberToHex;
|
|
1718
1853
|
exports.objectAssign = objectAssign;
|