sculp-js 0.1.1 → 1.0.1
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 +56 -36
- 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 +9 -3
- 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/tooltip.js +118 -0
- 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 +55 -35
- 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 +4 -3
- 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/tooltip.js +116 -0
- 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 +155 -66
- package/lib/tsdoc-metadata.json +11 -0
- package/lib/umd/index.js +365 -108
- 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,34 +275,42 @@
|
|
|
263
275
|
if (!isObject(any))
|
|
264
276
|
return false;
|
|
265
277
|
return objectHas(any, 'length');
|
|
266
|
-
}
|
|
278
|
+
}
|
|
267
279
|
/**
|
|
268
|
-
* 遍历数组,返回 false 中断遍历
|
|
280
|
+
* 遍历数组,返回 false 中断遍历(支持continue和break操作)
|
|
281
|
+
*
|
|
269
282
|
* @param {ArrayLike<V>} array
|
|
270
|
-
* @param {(val: V, idx: number) => any} iterator
|
|
271
|
-
* @param
|
|
283
|
+
* @param {(val: V, idx: number) => any} iterator 迭代函数, 返回值为true时continue, 返回值为false时break
|
|
284
|
+
* @param {boolean} reverse 是否倒序
|
|
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];
|
|
277
|
-
|
|
291
|
+
const re = iterator(val, idx, array);
|
|
292
|
+
if (re === false)
|
|
278
293
|
break;
|
|
294
|
+
else if (re === true)
|
|
295
|
+
continue;
|
|
279
296
|
}
|
|
280
297
|
}
|
|
281
298
|
else {
|
|
282
299
|
for (let idx = 0; idx < array.length; idx++) {
|
|
283
300
|
const val = array[idx];
|
|
284
|
-
|
|
301
|
+
const re = iterator(val, idx, array);
|
|
302
|
+
if (re === false)
|
|
285
303
|
break;
|
|
304
|
+
else if (re === true)
|
|
305
|
+
continue;
|
|
286
306
|
}
|
|
287
307
|
}
|
|
288
|
-
}
|
|
308
|
+
}
|
|
289
309
|
/**
|
|
290
310
|
* 异步遍历数组,返回 false 中断遍历
|
|
291
|
-
* @param {ArrayLike<V>} array
|
|
292
|
-
* @param {(val: V, idx: number) => Promise<any>} iterator
|
|
293
|
-
* @param {boolean} reverse
|
|
311
|
+
* @param {ArrayLike<V>} array 数组
|
|
312
|
+
* @param {(val: V, idx: number) => Promise<any>} iterator 支持Promise类型的回调函数
|
|
313
|
+
* @param {boolean} reverse 是否反向遍历
|
|
294
314
|
*/
|
|
295
315
|
async function arrayEachAsync(array, iterator, reverse = false) {
|
|
296
316
|
if (reverse) {
|
|
@@ -313,15 +333,16 @@
|
|
|
313
333
|
* @param {AnyArray} array
|
|
314
334
|
* @param {number} start
|
|
315
335
|
* @param {number} to
|
|
336
|
+
* @returns {*}
|
|
316
337
|
*/
|
|
317
|
-
|
|
338
|
+
function arrayInsertBefore(array, start, to) {
|
|
318
339
|
if (start === to || start + 1 === to)
|
|
319
340
|
return;
|
|
320
341
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
321
342
|
const [source] = array.splice(start, 1);
|
|
322
343
|
const insertIndex = to < start ? to : to - 1;
|
|
323
344
|
array.splice(insertIndex, 0, source);
|
|
324
|
-
}
|
|
345
|
+
}
|
|
325
346
|
/**
|
|
326
347
|
* 数组删除指定项目
|
|
327
348
|
* @param {V[]} array
|
|
@@ -342,21 +363,26 @@
|
|
|
342
363
|
}
|
|
343
364
|
/**
|
|
344
365
|
* 自定义深度优先遍历函数(支持continue和break操作)
|
|
345
|
-
* @param {
|
|
346
|
-
* @param {
|
|
347
|
-
* @param {
|
|
348
|
-
* @param {boolean} isReverse
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
366
|
+
* @param {ArrayLike<V>} tree 树形数据
|
|
367
|
+
* @param {Function} iterator 迭代函数, 返回值为true时continue, 返回值为false时break
|
|
368
|
+
* @param {string} children 定制子元素的key
|
|
369
|
+
* @param {boolean} isReverse 是否反向遍历
|
|
370
|
+
* @returns {*}
|
|
371
|
+
*/
|
|
372
|
+
function forEachDeep(tree, iterator, children = 'children', isReverse = false) {
|
|
373
|
+
let level = 0, isBreak = false;
|
|
352
374
|
const walk = (arr, parent) => {
|
|
353
375
|
if (isReverse) {
|
|
354
376
|
for (let i = arr.length - 1; i >= 0; i--) {
|
|
355
|
-
|
|
356
|
-
|
|
377
|
+
if (isBreak) {
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
const re = iterator(arr[i], i, tree, parent, level);
|
|
381
|
+
if (re === false) {
|
|
382
|
+
isBreak = true;
|
|
357
383
|
break;
|
|
358
384
|
}
|
|
359
|
-
else if (re ===
|
|
385
|
+
else if (re === true) {
|
|
360
386
|
continue;
|
|
361
387
|
}
|
|
362
388
|
// @ts-ignore
|
|
@@ -369,11 +395,15 @@
|
|
|
369
395
|
}
|
|
370
396
|
else {
|
|
371
397
|
for (let i = 0; i < arr.length; i++) {
|
|
372
|
-
|
|
373
|
-
if (re === 'break') {
|
|
398
|
+
if (isBreak) {
|
|
374
399
|
break;
|
|
375
400
|
}
|
|
376
|
-
|
|
401
|
+
const re = iterator(arr[i], i, tree, parent, level);
|
|
402
|
+
if (re === false) {
|
|
403
|
+
isBreak = true;
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
else if (re === true) {
|
|
377
407
|
continue;
|
|
378
408
|
}
|
|
379
409
|
// @ts-ignore
|
|
@@ -385,16 +415,17 @@
|
|
|
385
415
|
}
|
|
386
416
|
}
|
|
387
417
|
};
|
|
388
|
-
walk(
|
|
389
|
-
}
|
|
418
|
+
walk(tree, null);
|
|
419
|
+
}
|
|
390
420
|
/**
|
|
391
421
|
* 在树中找到 id 为某个值的节点,并返回上游的所有父级节点
|
|
392
|
-
*
|
|
393
|
-
* @param {
|
|
394
|
-
* @param {
|
|
395
|
-
* @
|
|
422
|
+
*
|
|
423
|
+
* @param {ArrayLike<T>} tree - 树形数据
|
|
424
|
+
* @param {IdLike} nodeId - 元素ID
|
|
425
|
+
* @param {ITreeConf} config - 迭代配置项
|
|
426
|
+
* @returns {[IdLike[], ITreeItem<V>[]]} - 由parentId...childId, parentObject-childObject组成的二维数组
|
|
396
427
|
*/
|
|
397
|
-
function
|
|
428
|
+
function searchTreeById(tree, nodeId, config) {
|
|
398
429
|
const { children = 'children', id = 'id' } = config || {};
|
|
399
430
|
const toFlatArray = (tree, parentId, parent) => {
|
|
400
431
|
return tree.reduce((t, _) => {
|
|
@@ -454,24 +485,24 @@
|
|
|
454
485
|
* @param {boolean} [bigger] 是否大写第一个字母
|
|
455
486
|
* @returns {string}
|
|
456
487
|
*/
|
|
457
|
-
|
|
488
|
+
function stringCamelCase(string, bigger) {
|
|
458
489
|
let string2 = string;
|
|
459
490
|
if (bigger) {
|
|
460
491
|
string2 = string.replace(/^./, origin => origin.toUpperCase());
|
|
461
492
|
}
|
|
462
493
|
const HUMP_RE = /[\s_-](.)/g;
|
|
463
494
|
return string2.replace(HUMP_RE, (orign, char) => char.toUpperCase());
|
|
464
|
-
}
|
|
495
|
+
}
|
|
465
496
|
/**
|
|
466
497
|
* 将字符串转换为连字格式
|
|
467
498
|
* @param {string} string
|
|
468
499
|
* @param {string} [separator] 分隔符,默认是"-"(短横线)
|
|
469
500
|
* @returns {string}
|
|
470
501
|
*/
|
|
471
|
-
|
|
502
|
+
function stringKebabCase(string, separator = '-') {
|
|
472
503
|
const string2 = string.replace(/^./, origin => origin.toLowerCase());
|
|
473
504
|
return string2.replace(/[A-Z]/g, origin => `${separator}${origin.toLowerCase()}`);
|
|
474
|
-
}
|
|
505
|
+
}
|
|
475
506
|
const STRING_ARABIC_NUMERALS = '0123456789';
|
|
476
507
|
const STRING_LOWERCASE_ALPHA = 'abcdefghijklmnopqrstuvwxyz';
|
|
477
508
|
const STRING_UPPERCASE_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
@@ -487,7 +518,7 @@
|
|
|
487
518
|
* @param args
|
|
488
519
|
* @returns {string}
|
|
489
520
|
*/
|
|
490
|
-
|
|
521
|
+
function stringFormat(string, ...args) {
|
|
491
522
|
let index = 0;
|
|
492
523
|
const result = string.replace(placeholderRE, (origin) => {
|
|
493
524
|
const arg = args[index++];
|
|
@@ -505,7 +536,7 @@
|
|
|
505
536
|
}
|
|
506
537
|
});
|
|
507
538
|
return [result, ...args.splice(index).map(String)].join(' ');
|
|
508
|
-
}
|
|
539
|
+
}
|
|
509
540
|
const ev = (expression, data) => {
|
|
510
541
|
try {
|
|
511
542
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval,@typescript-eslint/no-unsafe-return
|
|
@@ -569,7 +600,7 @@
|
|
|
569
600
|
* @param {string} str 目标字符串
|
|
570
601
|
* @param {number} fontSize 字符串字体大小
|
|
571
602
|
* @param {boolean} isRemoveDom 计算后是否移除中间dom元素
|
|
572
|
-
* @
|
|
603
|
+
* @returns {*}
|
|
573
604
|
*/
|
|
574
605
|
function getStrWidthPx(str, fontSize = 14, isRemoveDom = false) {
|
|
575
606
|
let strWidth = 0;
|
|
@@ -601,11 +632,11 @@
|
|
|
601
632
|
* @param {string} className
|
|
602
633
|
* @returns {boolean}
|
|
603
634
|
*/
|
|
604
|
-
|
|
635
|
+
function hasClass(el, className) {
|
|
605
636
|
if (className.indexOf(' ') !== -1)
|
|
606
637
|
throw new Error('className should not contain space.');
|
|
607
638
|
return el.classList.contains(className);
|
|
608
|
-
}
|
|
639
|
+
}
|
|
609
640
|
const eachClassName = (classNames, func) => {
|
|
610
641
|
const classNameList = classNames.split(/\s+/g);
|
|
611
642
|
classNameList.forEach(func);
|
|
@@ -615,17 +646,17 @@
|
|
|
615
646
|
* @param {HTMLElement} el
|
|
616
647
|
* @param {string} classNames
|
|
617
648
|
*/
|
|
618
|
-
|
|
649
|
+
function addClass(el, classNames) {
|
|
619
650
|
eachClassName(classNames, className => el.classList.add(className));
|
|
620
|
-
}
|
|
651
|
+
}
|
|
621
652
|
/**
|
|
622
653
|
* 给元素移除样式名
|
|
623
654
|
* @param {HTMLElement} el
|
|
624
655
|
* @param {string} classNames
|
|
625
656
|
*/
|
|
626
|
-
|
|
657
|
+
function removeClass(el, classNames) {
|
|
627
658
|
eachClassName(classNames, className => el.classList.remove(className));
|
|
628
|
-
}
|
|
659
|
+
}
|
|
629
660
|
/**
|
|
630
661
|
* 设置元素样式
|
|
631
662
|
* @param {HTMLElement} el
|
|
@@ -644,12 +675,14 @@
|
|
|
644
675
|
};
|
|
645
676
|
/**
|
|
646
677
|
* 获取元素样式
|
|
647
|
-
* @param {HTMLElement} el
|
|
678
|
+
* @param {HTMLElement} el 元素
|
|
648
679
|
* @param {string} key
|
|
649
680
|
* @returns {string}
|
|
650
681
|
*/
|
|
651
|
-
|
|
652
|
-
|
|
682
|
+
function getStyle(el, key) {
|
|
683
|
+
return getComputedStyle(el).getPropertyValue(key);
|
|
684
|
+
}
|
|
685
|
+
function smoothScroll(options) {
|
|
653
686
|
return new Promise(resolve => {
|
|
654
687
|
const defaults = {
|
|
655
688
|
el: document,
|
|
@@ -729,7 +762,7 @@
|
|
|
729
762
|
* @param {HTMLElement} el
|
|
730
763
|
* @param {string} property
|
|
731
764
|
* @param {boolean} reNumber
|
|
732
|
-
* @
|
|
765
|
+
* @returns {string|number}
|
|
733
766
|
*/
|
|
734
767
|
function getComputedCssVal(el, property, reNumber = true) {
|
|
735
768
|
const originVal = getComputedStyle(el).getPropertyValue(property) ?? '';
|
|
@@ -748,7 +781,7 @@
|
|
|
748
781
|
* 复制文本
|
|
749
782
|
* @param {string} text
|
|
750
783
|
*/
|
|
751
|
-
|
|
784
|
+
function copyText(text) {
|
|
752
785
|
textEl.value = text;
|
|
753
786
|
textEl.focus({ preventScroll: true });
|
|
754
787
|
textEl.select();
|
|
@@ -759,14 +792,14 @@
|
|
|
759
792
|
catch (err) {
|
|
760
793
|
// ignore
|
|
761
794
|
}
|
|
762
|
-
}
|
|
795
|
+
}
|
|
763
796
|
|
|
764
797
|
/**
|
|
765
798
|
* 获取cookie
|
|
766
799
|
* @param {string} name
|
|
767
800
|
* @returns {string}
|
|
768
801
|
*/
|
|
769
|
-
|
|
802
|
+
function cookieGet(name) {
|
|
770
803
|
const { cookie } = document;
|
|
771
804
|
if (!cookie)
|
|
772
805
|
return '';
|
|
@@ -778,14 +811,14 @@
|
|
|
778
811
|
return decodeURIComponent(val);
|
|
779
812
|
}
|
|
780
813
|
return '';
|
|
781
|
-
}
|
|
814
|
+
}
|
|
782
815
|
/**
|
|
783
816
|
* 设置 cookie
|
|
784
817
|
* @param {string} name
|
|
785
818
|
* @param {string} value
|
|
786
819
|
* @param {number | Date} [maxAge]
|
|
787
820
|
*/
|
|
788
|
-
|
|
821
|
+
function cookieSet(name, value, maxAge) {
|
|
789
822
|
const metas = [];
|
|
790
823
|
const EXPIRES = 'expires';
|
|
791
824
|
metas.push([name, encodeURIComponent(value)]);
|
|
@@ -804,13 +837,66 @@
|
|
|
804
837
|
return `${key}=${val}`;
|
|
805
838
|
})
|
|
806
839
|
.join(';');
|
|
807
|
-
}
|
|
840
|
+
}
|
|
808
841
|
/**
|
|
809
842
|
* 删除单个 cookie
|
|
810
843
|
* @param name cookie 名称
|
|
811
844
|
*/
|
|
812
845
|
const cookieDel = (name) => cookieSet(name, '', -1);
|
|
813
846
|
|
|
847
|
+
const isValidDate = (any) => isDate(any) && !isNaN(any.getTime());
|
|
848
|
+
/* istanbul ignore next */
|
|
849
|
+
const guessDateSeparator = (value) => {
|
|
850
|
+
if (!isString(value))
|
|
851
|
+
return;
|
|
852
|
+
const value2 = value.replace(/-/g, '/');
|
|
853
|
+
return new Date(value2);
|
|
854
|
+
};
|
|
855
|
+
/* istanbul ignore next */
|
|
856
|
+
const guessDateTimezone = (value) => {
|
|
857
|
+
if (!isString(value))
|
|
858
|
+
return;
|
|
859
|
+
const re = /([+-])(\d\d)(\d\d)$/;
|
|
860
|
+
const matches = re.exec(value);
|
|
861
|
+
if (!matches)
|
|
862
|
+
return;
|
|
863
|
+
const value2 = value.replace(re, 'Z');
|
|
864
|
+
const d = new Date(value2);
|
|
865
|
+
if (!isValidDate(d))
|
|
866
|
+
return;
|
|
867
|
+
const [, flag, hours, minutes] = matches;
|
|
868
|
+
const hours2 = parseInt(hours, 10);
|
|
869
|
+
const minutes2 = parseInt(minutes, 10);
|
|
870
|
+
const offset = (a, b) => (flag === '+' ? a - b : a + b);
|
|
871
|
+
d.setHours(offset(d.getHours(), hours2));
|
|
872
|
+
d.setMinutes(offset(d.getMinutes(), minutes2));
|
|
873
|
+
return d;
|
|
874
|
+
};
|
|
875
|
+
/**
|
|
876
|
+
* 解析为Date对象
|
|
877
|
+
* @param {DateValue} value - 可以是数值、字符串或 Date 对象
|
|
878
|
+
* @returns {Date} - 转换后的目标Date
|
|
879
|
+
*/
|
|
880
|
+
function dateParse(value) {
|
|
881
|
+
const d1 = new Date(value);
|
|
882
|
+
if (isValidDate(d1))
|
|
883
|
+
return d1;
|
|
884
|
+
// safari 浏览器的日期解析有问题
|
|
885
|
+
// new Date('2020-06-26 18:06:15') 返回值是一个非法日期对象
|
|
886
|
+
/* istanbul ignore next */
|
|
887
|
+
const d2 = guessDateSeparator(value);
|
|
888
|
+
/* istanbul ignore next */
|
|
889
|
+
if (isValidDate(d2))
|
|
890
|
+
return d2;
|
|
891
|
+
// safari 浏览器的日期解析有问题
|
|
892
|
+
// new Date('2020-06-26T18:06:15.000+0800') 返回值是一个非法日期对象
|
|
893
|
+
/* istanbul ignore next */
|
|
894
|
+
const d3 = guessDateTimezone(value);
|
|
895
|
+
/* istanbul ignore next */
|
|
896
|
+
if (isValidDate(d3))
|
|
897
|
+
return d3;
|
|
898
|
+
throw new SyntaxError(`${value.toString()} 不是一个合法的日期描述`);
|
|
899
|
+
}
|
|
814
900
|
/**
|
|
815
901
|
* 格式化为日期对象(带自定义格式化模板)
|
|
816
902
|
* @param {DateValue} value 可以是数值、字符串或 Date 对象
|
|
@@ -825,10 +911,69 @@
|
|
|
825
911
|
* - mm:分
|
|
826
912
|
* - ss:秒
|
|
827
913
|
* - SSS:毫秒
|
|
828
|
-
* - ww: 周
|
|
829
914
|
* @returns {string}
|
|
830
915
|
*/
|
|
831
|
-
const
|
|
916
|
+
// export const dateStringify = (value: DateValue, format = 'YYYY-MM-DD HH:mm:ss'): string => {
|
|
917
|
+
// const date = dateParse(value);
|
|
918
|
+
// let fmt = format;
|
|
919
|
+
// let ret;
|
|
920
|
+
// const opt: DateObj = {
|
|
921
|
+
// 'Y+': `${date.getFullYear()}`, // 年
|
|
922
|
+
// 'y+': `${date.getFullYear()}`, // 年
|
|
923
|
+
// 'M+': `${date.getMonth() + 1}`, // 月
|
|
924
|
+
// 'D+': `${date.getDate()}`, // 日
|
|
925
|
+
// 'd+': `${date.getDate()}`, // 日
|
|
926
|
+
// 'H+': `${date.getHours()}`, // 时
|
|
927
|
+
// 'm+': `${date.getMinutes()}`, // 分
|
|
928
|
+
// 's+': `${date.getSeconds()}`, // 秒
|
|
929
|
+
// 'S+': `${date.getMilliseconds()}` // 豪秒
|
|
930
|
+
// };
|
|
931
|
+
// for (const k in opt) {
|
|
932
|
+
// ret = new RegExp(`(${k})`).exec(fmt);
|
|
933
|
+
// if (ret) {
|
|
934
|
+
// fmt = fmt.replace(ret[1], ret[1].length === 1 ? opt[k] : opt[k].padStart(ret[1].length, '0'));
|
|
935
|
+
// }
|
|
936
|
+
// }
|
|
937
|
+
// return fmt;
|
|
938
|
+
// };
|
|
939
|
+
/**
|
|
940
|
+
* 将日期转换为一天的开始时间,即0点0分0秒0毫秒
|
|
941
|
+
* @param {DateValue} value
|
|
942
|
+
* @returns {Date}
|
|
943
|
+
*/
|
|
944
|
+
function dateToStart(value) {
|
|
945
|
+
const d = dateParse(value);
|
|
946
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0);
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* 将日期转换为一天的结束时间,即23点59分59秒999毫秒
|
|
950
|
+
* @param {DateValue} value
|
|
951
|
+
* @returns {Date}
|
|
952
|
+
*/
|
|
953
|
+
function dateToEnd(value) {
|
|
954
|
+
const d = dateToStart(value);
|
|
955
|
+
d.setDate(d.getDate() + 1);
|
|
956
|
+
return dateParse(d.getTime() - 1);
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* 格式化为日期对象(带自定义格式化模板)
|
|
960
|
+
* @param {Date} value - 可以是数值、字符串或 Date 对象
|
|
961
|
+
* @param {string} [format] - 模板,默认是 YYYY-MM-DD HH:mm:ss,模板字符:
|
|
962
|
+
* - YYYY:年
|
|
963
|
+
* - yyyy: 年
|
|
964
|
+
* - MM:月
|
|
965
|
+
* - DD:日
|
|
966
|
+
* - dd: 日
|
|
967
|
+
* - HH:时(24 小时制)
|
|
968
|
+
* - hh:时(12 小时制)
|
|
969
|
+
* - mm:分
|
|
970
|
+
* - ss:秒
|
|
971
|
+
* - SSS:毫秒
|
|
972
|
+
* - ww: 周
|
|
973
|
+
* @returns {string} 格式化后的日期字符串
|
|
974
|
+
*/
|
|
975
|
+
function formatDate(value, format = 'YYYY-MM-DD HH:mm:ss') {
|
|
976
|
+
const date = dateParse(value);
|
|
832
977
|
let fmt = format;
|
|
833
978
|
let ret;
|
|
834
979
|
const opt = {
|
|
@@ -851,13 +996,13 @@
|
|
|
851
996
|
}
|
|
852
997
|
}
|
|
853
998
|
return fmt;
|
|
854
|
-
}
|
|
999
|
+
}
|
|
855
1000
|
/**
|
|
856
1001
|
* 计算向前或向后N天的具体日期
|
|
857
|
-
* @param {string} strDate 参考日期
|
|
858
|
-
* @param {number} n 正数:向后推算;负数:向前推算
|
|
859
|
-
* @param {string} sep 日期格式的分隔符
|
|
860
|
-
* @
|
|
1002
|
+
* @param {string} strDate - 参考日期
|
|
1003
|
+
* @param {number} n - 正数:向后推算;负数:向前推算
|
|
1004
|
+
* @param {string} sep - 日期格式的分隔符
|
|
1005
|
+
* @returns {string} 计算后的目标日期
|
|
861
1006
|
*/
|
|
862
1007
|
function calculateDate(strDate, n, sep = '-') {
|
|
863
1008
|
//strDate 为字符串日期 如:'2019-01-01' n为你要传入的参数,当前为0,前一天为-1,后一天为1
|
|
@@ -875,10 +1020,10 @@
|
|
|
875
1020
|
}
|
|
876
1021
|
/**
|
|
877
1022
|
* 计算向前或向后N天的具体时间日期
|
|
878
|
-
* @param {number} n 正数:向后推算;负数:向前推算
|
|
879
|
-
* @param {string} dateSep 日期分隔符
|
|
880
|
-
* @param {string} timeSep 时间分隔符
|
|
881
|
-
* @
|
|
1023
|
+
* @param {number} n - 正数:向后推算;负数:向前推算
|
|
1024
|
+
* @param {string} dateSep - 日期分隔符
|
|
1025
|
+
* @param {string} timeSep - 时间分隔符
|
|
1026
|
+
* @returns {string} 转换后的目标日期时间
|
|
882
1027
|
*/
|
|
883
1028
|
function calculateDateTime(n, dateSep = '-', timeSep = ':') {
|
|
884
1029
|
const date = new Date();
|
|
@@ -975,7 +1120,7 @@
|
|
|
975
1120
|
* @param {string} queryString
|
|
976
1121
|
* @returns {Params}
|
|
977
1122
|
*/
|
|
978
|
-
|
|
1123
|
+
function qsParse(queryString) {
|
|
979
1124
|
const params = new URLSearchParams(queryString);
|
|
980
1125
|
const result = {};
|
|
981
1126
|
for (const [key, val] of params.entries()) {
|
|
@@ -989,7 +1134,7 @@
|
|
|
989
1134
|
result[key] = params.getAll(key);
|
|
990
1135
|
}
|
|
991
1136
|
return result;
|
|
992
|
-
}
|
|
1137
|
+
}
|
|
993
1138
|
const defaultReplacer = (val) => {
|
|
994
1139
|
if (isString(val))
|
|
995
1140
|
return val;
|
|
@@ -1007,7 +1152,7 @@
|
|
|
1007
1152
|
* @param {Replacer} replacer
|
|
1008
1153
|
* @returns {string}
|
|
1009
1154
|
*/
|
|
1010
|
-
|
|
1155
|
+
function qsStringify(query, replacer = defaultReplacer) {
|
|
1011
1156
|
const params = new URLSearchParams();
|
|
1012
1157
|
objectEach(query, (val, key) => {
|
|
1013
1158
|
if (isArray(val)) {
|
|
@@ -1026,7 +1171,7 @@
|
|
|
1026
1171
|
}
|
|
1027
1172
|
});
|
|
1028
1173
|
return params.toString();
|
|
1029
|
-
}
|
|
1174
|
+
}
|
|
1030
1175
|
|
|
1031
1176
|
const anchorEl = document.createElement('a');
|
|
1032
1177
|
/**
|
|
@@ -1102,15 +1247,15 @@
|
|
|
1102
1247
|
* @param {string} url
|
|
1103
1248
|
* @param {LooseParams} params
|
|
1104
1249
|
*/
|
|
1105
|
-
|
|
1250
|
+
function downloadURL(url, params) {
|
|
1106
1251
|
window.open(params ? urlSetParams(url, params) : url);
|
|
1107
|
-
}
|
|
1252
|
+
}
|
|
1108
1253
|
/**
|
|
1109
1254
|
* 通过 A 链接的方式下载
|
|
1110
1255
|
* @param {string} href
|
|
1111
1256
|
* @param {string} filename
|
|
1112
1257
|
*/
|
|
1113
|
-
|
|
1258
|
+
function downloadHref(href, filename) {
|
|
1114
1259
|
const eleLink = document.createElement('a');
|
|
1115
1260
|
eleLink.download = filename;
|
|
1116
1261
|
eleLink.style.display = 'none';
|
|
@@ -1118,17 +1263,17 @@
|
|
|
1118
1263
|
document.body.appendChild(eleLink);
|
|
1119
1264
|
eleLink.click();
|
|
1120
1265
|
setTimeout(() => document.body.removeChild(eleLink));
|
|
1121
|
-
}
|
|
1266
|
+
}
|
|
1122
1267
|
/**
|
|
1123
1268
|
* 将大文件对象通过 A 链接的方式下载
|
|
1124
1269
|
* @param {Blob} blob
|
|
1125
1270
|
* @param {string} filename
|
|
1126
1271
|
*/
|
|
1127
|
-
|
|
1272
|
+
function downloadBlob(blob, filename) {
|
|
1128
1273
|
const objURL = URL.createObjectURL(blob);
|
|
1129
1274
|
downloadHref(objURL, filename);
|
|
1130
1275
|
setTimeout(() => URL.revokeObjectURL(objURL));
|
|
1131
|
-
}
|
|
1276
|
+
}
|
|
1132
1277
|
/**
|
|
1133
1278
|
* 将指定数据格式通过 A 链接的方式下载
|
|
1134
1279
|
* @param {AnyObject | AnyObject[]} data
|
|
@@ -1136,7 +1281,7 @@
|
|
|
1136
1281
|
* @param {string} filename
|
|
1137
1282
|
* @param {string[]} [headers]
|
|
1138
1283
|
*/
|
|
1139
|
-
|
|
1284
|
+
function downloadData(data, fileType, filename, headers) {
|
|
1140
1285
|
filename = filename.replace(`.${fileType}`, '') + `.${fileType}`;
|
|
1141
1286
|
if (fileType === 'json') {
|
|
1142
1287
|
const blob = new Blob([JSON.stringify(data, null, 4)]);
|
|
@@ -1163,14 +1308,14 @@
|
|
|
1163
1308
|
const href = 'data:' + MIMETypes[fileType] + ';charset=utf-8,\ufeff' + encodeURIComponent(headerStr + bodyStr);
|
|
1164
1309
|
downloadHref(href, filename);
|
|
1165
1310
|
}
|
|
1166
|
-
}
|
|
1311
|
+
}
|
|
1167
1312
|
|
|
1168
1313
|
/**
|
|
1169
1314
|
* 等待一段时间
|
|
1170
1315
|
* @param {number} timeout 等待时间,单位毫秒
|
|
1171
1316
|
* @returns {Promise<void>}
|
|
1172
1317
|
*/
|
|
1173
|
-
|
|
1318
|
+
function wait(timeout = 1) {
|
|
1174
1319
|
return new Promise(resolve => setTimeout(resolve, timeout));
|
|
1175
1320
|
}
|
|
1176
1321
|
/**
|
|
@@ -1182,7 +1327,7 @@
|
|
|
1182
1327
|
* @param {number} concurrency 并发数量,默认无限
|
|
1183
1328
|
* @returns {Promise<R[]>}
|
|
1184
1329
|
*/
|
|
1185
|
-
|
|
1330
|
+
function asyncMap(list, mapper, concurrency = Infinity) {
|
|
1186
1331
|
return new Promise((resolve, reject) => {
|
|
1187
1332
|
const iterator = list[Symbol.iterator]();
|
|
1188
1333
|
const limit = Math.min(list.length, concurrency);
|
|
@@ -1220,10 +1365,11 @@
|
|
|
1220
1365
|
|
|
1221
1366
|
/**
|
|
1222
1367
|
* 选择本地文件
|
|
1223
|
-
* @param {
|
|
1224
|
-
* @
|
|
1368
|
+
* @param {string} accept 上传的文件类型,用于过滤
|
|
1369
|
+
* @param {Function} changeCb 选择文件回调
|
|
1370
|
+
* @returns {HTMLInputElement}
|
|
1225
1371
|
*/
|
|
1226
|
-
function chooseLocalFile(
|
|
1372
|
+
function chooseLocalFile(accept, changeCb) {
|
|
1227
1373
|
const inputObj = document.createElement('input');
|
|
1228
1374
|
inputObj.setAttribute('id', String(Date.now()));
|
|
1229
1375
|
inputObj.setAttribute('type', 'file');
|
|
@@ -1246,17 +1392,18 @@
|
|
|
1246
1392
|
* @desc 网页加水印的工具类
|
|
1247
1393
|
*/
|
|
1248
1394
|
/**
|
|
1249
|
-
* canvas 实现
|
|
1395
|
+
* canvas 实现 水印, 具备防删除功能
|
|
1250
1396
|
* @param {ICanvasWM} canvasWM
|
|
1397
|
+
* @example genCanvasWM({ content: 'QQMusicFE' })
|
|
1251
1398
|
*/
|
|
1252
|
-
|
|
1399
|
+
function genCanvasWM(canvasWM) {
|
|
1253
1400
|
const { container = document.body, width = '300px', height = '200px', textAlign = 'center', textBaseline = 'middle', font = '20px PingFangSC-Medium,PingFang SC',
|
|
1254
1401
|
// fontWeight = 500,
|
|
1255
1402
|
fillStyle = 'rgba(189, 177, 167, .3)', content = '请勿外传', rotate = 30, zIndex = 2147483647 } = canvasWM;
|
|
1256
1403
|
// 仅限主页面添加水印
|
|
1257
|
-
if (!location.pathname.includes('/home')) {
|
|
1258
|
-
|
|
1259
|
-
}
|
|
1404
|
+
// if (!location.pathname.includes('/home')) {
|
|
1405
|
+
// return;
|
|
1406
|
+
// }
|
|
1260
1407
|
const args = canvasWM;
|
|
1261
1408
|
const canvas = document.createElement('canvas');
|
|
1262
1409
|
canvas.setAttribute('width', width);
|
|
@@ -1317,9 +1464,7 @@
|
|
|
1317
1464
|
});
|
|
1318
1465
|
mo.observe(container, { attributes: true, subtree: true, childList: true });
|
|
1319
1466
|
}
|
|
1320
|
-
}
|
|
1321
|
-
// 调用
|
|
1322
|
-
// __canvasWM({ content: 'QQMusicFE' })
|
|
1467
|
+
}
|
|
1323
1468
|
|
|
1324
1469
|
/**
|
|
1325
1470
|
* 防抖函数
|
|
@@ -1537,7 +1682,7 @@
|
|
|
1537
1682
|
* @param {string} [hexPool] 进制池,默认 62 进制
|
|
1538
1683
|
* @returns {string}
|
|
1539
1684
|
*/
|
|
1540
|
-
|
|
1685
|
+
function numberToHex(decimal, hexPool = HEX_POOL) {
|
|
1541
1686
|
if (hexPool.length < 2)
|
|
1542
1687
|
throw new Error('进制池长度不能少于 2');
|
|
1543
1688
|
if (!supportBigInt) {
|
|
@@ -1559,7 +1704,7 @@
|
|
|
1559
1704
|
};
|
|
1560
1705
|
execute();
|
|
1561
1706
|
return ret.join('');
|
|
1562
|
-
}
|
|
1707
|
+
}
|
|
1563
1708
|
/**
|
|
1564
1709
|
* 缩写
|
|
1565
1710
|
* @param {number | string} num
|
|
@@ -1586,7 +1731,7 @@
|
|
|
1586
1731
|
* 将数字格式化成千位分隔符显示的字符串
|
|
1587
1732
|
* @param {number} val 数字
|
|
1588
1733
|
* @param {'int' | 'float'} type 展示分段显示的类型 int:整型 | float:浮点型
|
|
1589
|
-
* @
|
|
1734
|
+
* @returns {string}
|
|
1590
1735
|
*/
|
|
1591
1736
|
function formatNumber(val, type = 'int') {
|
|
1592
1737
|
return type === 'int' ? parseInt(String(val)).toLocaleString() : Number(val).toLocaleString('en-US');
|
|
@@ -1660,6 +1805,113 @@
|
|
|
1660
1805
|
return uniqueString;
|
|
1661
1806
|
};
|
|
1662
1807
|
|
|
1808
|
+
/**
|
|
1809
|
+
* @title tooltip
|
|
1810
|
+
* @Desc 自定义的tooltip方法, 支持拖动悬浮提示
|
|
1811
|
+
* Created by chendeqiao on 2017/5/8.
|
|
1812
|
+
* @example
|
|
1813
|
+
* <span onmouseleave="handleMouseLeave('#root')" onmousemove="handleMouseEnter({rootElId: '#root', title: 'title content', event: event})"
|
|
1814
|
+
* onmouseenter="handleMouseEnter({'#root', title: 'title content', event: event})">title content </span>
|
|
1815
|
+
*/
|
|
1816
|
+
/**
|
|
1817
|
+
* 自定义title提示功能的mouseenter事件句柄
|
|
1818
|
+
* @param {ITooltipParams} param1
|
|
1819
|
+
* @returns {*}
|
|
1820
|
+
*/
|
|
1821
|
+
function handleMouseEnter({ rootElId = '#root', title, event }) {
|
|
1822
|
+
try {
|
|
1823
|
+
const $rootEl = document.querySelector(rootElId);
|
|
1824
|
+
console.assert($rootEl !== null, `未找到id为 ${rootElId} 的dom元素`);
|
|
1825
|
+
let $customTitle = null;
|
|
1826
|
+
// 动态创建class样式,并加入到head中
|
|
1827
|
+
if (!document.querySelector('.tooltip-inner1494304949567')) {
|
|
1828
|
+
const tooltipWrapperClass = document.createElement('style');
|
|
1829
|
+
tooltipWrapperClass.type = 'text/css';
|
|
1830
|
+
tooltipWrapperClass.innerHTML = `
|
|
1831
|
+
.tooltip-inner1494304949567 {
|
|
1832
|
+
max-width: 250px;
|
|
1833
|
+
padding: 3px 8px;
|
|
1834
|
+
color: #fff;
|
|
1835
|
+
text-decoration: none;
|
|
1836
|
+
border-radius: 4px;
|
|
1837
|
+
text-align: left;
|
|
1838
|
+
}
|
|
1839
|
+
`;
|
|
1840
|
+
document.querySelector('head').appendChild(tooltipWrapperClass);
|
|
1841
|
+
}
|
|
1842
|
+
if (document.querySelector('#customTitle1494304949567')) {
|
|
1843
|
+
$customTitle = document.querySelector('#customTitle1494304949567');
|
|
1844
|
+
mouseenter($customTitle, title, event);
|
|
1845
|
+
}
|
|
1846
|
+
else {
|
|
1847
|
+
const $contentContainer = document.createElement('div');
|
|
1848
|
+
$contentContainer.className = 'customTitle';
|
|
1849
|
+
$contentContainer.id = 'customTitle1494304949567';
|
|
1850
|
+
$contentContainer.className = 'tooltip';
|
|
1851
|
+
$contentContainer.style.cssText = 'z-index: 99999999; visibility: hidden;';
|
|
1852
|
+
$contentContainer.innerHTML =
|
|
1853
|
+
'<div class="tooltip-inner1494304949567" style="word-wrap: break-word; max-width: 44px;">皮肤</div>';
|
|
1854
|
+
$rootEl.appendChild($contentContainer);
|
|
1855
|
+
$customTitle = document.querySelector('#customTitle1494304949567');
|
|
1856
|
+
if (title) {
|
|
1857
|
+
//判断div显示的内容是否为空
|
|
1858
|
+
mouseenter($customTitle, title, event);
|
|
1859
|
+
$customTitle.style.visibility = 'visible';
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
catch (e) {
|
|
1864
|
+
console.error(e.message);
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
/**
|
|
1868
|
+
* 提示文案dom渲染的处理函数
|
|
1869
|
+
* @param {HTMLDivElement} customTitle
|
|
1870
|
+
* @param {string} title 提示的字符串
|
|
1871
|
+
* @param {PointerEvent} e 事件对象
|
|
1872
|
+
* @returns {*}
|
|
1873
|
+
*/
|
|
1874
|
+
function mouseenter($customTitle, title, e) {
|
|
1875
|
+
let diffValueX = 200 + 50; //默认设置弹出div的宽度为250px
|
|
1876
|
+
let x = 13;
|
|
1877
|
+
const y = 23;
|
|
1878
|
+
const $contentEle = $customTitle.children[0];
|
|
1879
|
+
if (getStrWidthPx(title, 12) < 180 + 50) {
|
|
1880
|
+
//【弹出div自适应字符串宽度】若显示的字符串占用宽度小于180,则设置弹出div的宽度为“符串占用宽度”+20
|
|
1881
|
+
$contentEle.style.maxWidth = getStrWidthPx(title, 12) + 20 + 50 + 'px';
|
|
1882
|
+
diffValueX = e.clientX + (getStrWidthPx(title, 12) + 50) - document.body.offsetWidth;
|
|
1883
|
+
}
|
|
1884
|
+
else {
|
|
1885
|
+
$contentEle.style.maxWidth = '250px';
|
|
1886
|
+
diffValueX = e.clientX + 230 - document.body.offsetWidth; //计算div水平方向显示的内容超出屏幕多少宽度
|
|
1887
|
+
}
|
|
1888
|
+
$contentEle.innerHTML = title; //html方法可解析内容中换行标签,text方法不能
|
|
1889
|
+
if (diffValueX > 0) {
|
|
1890
|
+
//水平方向超出可见区域时
|
|
1891
|
+
x -= diffValueX;
|
|
1892
|
+
}
|
|
1893
|
+
$customTitle.style.top = e.clientY + y + 'px';
|
|
1894
|
+
$customTitle.style.left = e.clientX + x + 'px';
|
|
1895
|
+
$customTitle.style.maxWidth = '250px';
|
|
1896
|
+
const diffValueY = $customTitle.getBoundingClientRect().top + $contentEle.offsetHeight - document.body.offsetHeight;
|
|
1897
|
+
if (diffValueY > 0) {
|
|
1898
|
+
//垂直方向超出可见区域时
|
|
1899
|
+
$customTitle.style.top = e.clientY - diffValueY + 'px';
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* 移除提示文案dom的事件句柄
|
|
1904
|
+
* @param {string} rootElId
|
|
1905
|
+
* @returns {*}
|
|
1906
|
+
*/
|
|
1907
|
+
function handleMouseLeave(rootElId = '#root') {
|
|
1908
|
+
const rootEl = document.querySelector(rootElId), titleEl = document.querySelector('#customTitle1494304949567');
|
|
1909
|
+
if (rootEl && titleEl) {
|
|
1910
|
+
rootEl.removeChild(titleEl);
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
const tooltipEvent = { handleMouseEnter, handleMouseLeave };
|
|
1914
|
+
|
|
1663
1915
|
exports.HEX_POOL = HEX_POOL;
|
|
1664
1916
|
exports.STRING_ARABIC_NUMERALS = STRING_ARABIC_NUMERALS;
|
|
1665
1917
|
exports.STRING_LOWERCASE_ALPHA = STRING_LOWERCASE_ALPHA;
|
|
@@ -1681,12 +1933,15 @@
|
|
|
1681
1933
|
exports.cookieGet = cookieGet;
|
|
1682
1934
|
exports.cookieSet = cookieSet;
|
|
1683
1935
|
exports.copyText = copyText;
|
|
1936
|
+
exports.dateParse = dateParse;
|
|
1937
|
+
exports.dateToEnd = dateToEnd;
|
|
1938
|
+
exports.dateToStart = dateToStart;
|
|
1684
1939
|
exports.debounce = debounce;
|
|
1685
|
-
exports.deepTraversal = deepTraversal;
|
|
1686
1940
|
exports.downloadBlob = downloadBlob;
|
|
1687
1941
|
exports.downloadData = downloadData;
|
|
1688
1942
|
exports.downloadHref = downloadHref;
|
|
1689
1943
|
exports.downloadURL = downloadURL;
|
|
1944
|
+
exports.forEachDeep = forEachDeep;
|
|
1690
1945
|
exports.formatDate = formatDate;
|
|
1691
1946
|
exports.formatNumber = formatNumber;
|
|
1692
1947
|
exports.genCanvasWM = genCanvasWM;
|
|
@@ -1694,7 +1949,6 @@
|
|
|
1694
1949
|
exports.getGlobal = getGlobal;
|
|
1695
1950
|
exports.getStrWidthPx = getStrWidthPx;
|
|
1696
1951
|
exports.getStyle = getStyle;
|
|
1697
|
-
exports.getTreeIds = getTreeIds;
|
|
1698
1952
|
exports.hasClass = hasClass;
|
|
1699
1953
|
exports.isArray = isArray;
|
|
1700
1954
|
exports.isBigInt = isBigInt;
|
|
@@ -1713,6 +1967,7 @@
|
|
|
1713
1967
|
exports.isString = isString;
|
|
1714
1968
|
exports.isSymbol = isSymbol;
|
|
1715
1969
|
exports.isUndefined = isUndefined;
|
|
1970
|
+
exports.isValidDate = isValidDate;
|
|
1716
1971
|
exports.numberAbbr = numberAbbr;
|
|
1717
1972
|
exports.numberToHex = numberToHex;
|
|
1718
1973
|
exports.objectAssign = objectAssign;
|
|
@@ -1735,6 +1990,7 @@
|
|
|
1735
1990
|
exports.randomString = randomString;
|
|
1736
1991
|
exports.randomUuid = randomUuid;
|
|
1737
1992
|
exports.removeClass = removeClass;
|
|
1993
|
+
exports.searchTreeById = searchTreeById;
|
|
1738
1994
|
exports.setGlobal = setGlobal;
|
|
1739
1995
|
exports.setStyle = setStyle;
|
|
1740
1996
|
exports.smoothScroll = smoothScroll;
|
|
@@ -1745,6 +2001,7 @@
|
|
|
1745
2001
|
exports.stringFormat = stringFormat;
|
|
1746
2002
|
exports.stringKebabCase = stringKebabCase;
|
|
1747
2003
|
exports.throttle = throttle;
|
|
2004
|
+
exports.tooltipEvent = tooltipEvent;
|
|
1748
2005
|
exports.typeIs = typeIs;
|
|
1749
2006
|
exports.uniqueNumber = uniqueNumber;
|
|
1750
2007
|
exports.uniqueString = uniqueString;
|