mazey 3.3.5 → 3.3.7
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 +5 -38
- package/examples/index.ts +43 -23
- package/lib/index.cjs.js +2 -2
- package/lib/index.d.ts +3 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.esm.js +2 -2
- package/lib/mazey.min.js +2 -2
- package/package.json +5 -3
- package/scripts/dev.js +12 -9
- package/scripts/github-helper.js +61 -1
- package/scripts/release.js +3 -1
- package/src/index.ts +400 -273
- package/src/{index.js → preview.js} +0 -0
- package/src/t.html +18 -0
package/src/index.ts
CHANGED
|
@@ -37,7 +37,10 @@ export function calLongestCommonSubstring(aStr: string, bStr: string): number {
|
|
|
37
37
|
* @param {string} bStr 字符串
|
|
38
38
|
* @returns {number} 长度
|
|
39
39
|
*/
|
|
40
|
-
export function calLongestCommonSubsequence(
|
|
40
|
+
export function calLongestCommonSubsequence(
|
|
41
|
+
aStr: string,
|
|
42
|
+
bStr: string
|
|
43
|
+
): number {
|
|
41
44
|
const aLen = aStr.length;
|
|
42
45
|
const bLen = bStr.length;
|
|
43
46
|
// 创建二维数组并且深拷贝
|
|
@@ -76,13 +79,13 @@ export function calLongestCommonSubsequence(aStr: string, bStr: string): number
|
|
|
76
79
|
* @returns {string} value
|
|
77
80
|
*/
|
|
78
81
|
export function getQueryParam(param: string): string {
|
|
79
|
-
const reg = new RegExp(
|
|
82
|
+
const reg = new RegExp("(^|&)" + param + "=([^&]*)(&|$)");
|
|
80
83
|
const r = location.search.substr(1).match(reg);
|
|
81
84
|
if (r !== null) {
|
|
82
85
|
// return decodeURIComponent(unescape(r[2]));
|
|
83
86
|
return decodeURIComponent(r[2]);
|
|
84
87
|
}
|
|
85
|
-
return
|
|
88
|
+
return "";
|
|
86
89
|
}
|
|
87
90
|
|
|
88
91
|
/**
|
|
@@ -97,7 +100,7 @@ export function getUrlParam(url: string, param: string): string | string[] {
|
|
|
97
100
|
[key: string]: string | string[] | any;
|
|
98
101
|
} = {};
|
|
99
102
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace
|
|
100
|
-
url.replace(/\??(\w+)=([^&]*)&?/g, function
|
|
103
|
+
url.replace(/\??(\w+)=([^&]*)&?/g, function(a, k, v): any {
|
|
101
104
|
if (result[k] !== undefined) {
|
|
102
105
|
const t = result[k];
|
|
103
106
|
result[k] = [].concat(t, v);
|
|
@@ -110,7 +113,7 @@ export function getUrlParam(url: string, param: string): string | string[] {
|
|
|
110
113
|
// } else {
|
|
111
114
|
// return result[param] || '';
|
|
112
115
|
// }
|
|
113
|
-
return result[param] ||
|
|
116
|
+
return result[param] || "";
|
|
114
117
|
}
|
|
115
118
|
|
|
116
119
|
/**
|
|
@@ -121,13 +124,17 @@ export function getUrlParam(url: string, param: string): string | string[] {
|
|
|
121
124
|
* @param {string} value Param's value.
|
|
122
125
|
* @returns {string} URL.
|
|
123
126
|
*/
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
export function updateQueryParam(
|
|
128
|
+
url: string,
|
|
129
|
+
param: string,
|
|
130
|
+
value: string
|
|
131
|
+
): string {
|
|
132
|
+
const re = new RegExp("([?&])" + param + "=.*?(&|$)", "i");
|
|
133
|
+
const separator = url.indexOf("?") !== -1 ? "&" : "?";
|
|
127
134
|
if (url.match(re)) {
|
|
128
|
-
return url.replace(re,
|
|
135
|
+
return url.replace(re, "$1" + param + "=" + value + "$2");
|
|
129
136
|
} else {
|
|
130
|
-
return url + separator + param +
|
|
137
|
+
return url + separator + param + "=" + value;
|
|
131
138
|
}
|
|
132
139
|
}
|
|
133
140
|
|
|
@@ -138,13 +145,13 @@ export function getUrlParam(url: string, param: string): string | string[] {
|
|
|
138
145
|
* @returns {string} value
|
|
139
146
|
*/
|
|
140
147
|
export function getHashQueryParam(param: string): string {
|
|
141
|
-
const hashs = location.hash.split(
|
|
148
|
+
const hashs = location.hash.split("?");
|
|
142
149
|
if (hashs.length === 1) {
|
|
143
|
-
return
|
|
150
|
+
return "";
|
|
144
151
|
}
|
|
145
152
|
const reg = new RegExp(`(^|&)${param}=([^&]*)(&|$)`);
|
|
146
153
|
const ret = hashs[1].match(reg);
|
|
147
|
-
return ret ? ret[2] :
|
|
154
|
+
return ret ? ret[2] : "";
|
|
148
155
|
}
|
|
149
156
|
|
|
150
157
|
/**
|
|
@@ -153,13 +160,13 @@ export function getHashQueryParam(param: string): string {
|
|
|
153
160
|
* @param {string} url
|
|
154
161
|
* @param {array} rules Object.keys(location), ['href', 'protocol', 'host', 'hostname', 'port', 'pathname', 'search', 'hash'], ['hostname', 'pathname'] = 'km.mazey.net/plugins/servlet/mobile'
|
|
155
162
|
*/
|
|
156
|
-
export function getDomain(url: string, rules = [
|
|
157
|
-
const aEl: any = document.createElement(
|
|
163
|
+
export function getDomain(url: string, rules = ["hostname"]): string {
|
|
164
|
+
const aEl: any = document.createElement("a");
|
|
158
165
|
aEl.href = url;
|
|
159
166
|
return rules.reduce((ret, v) => {
|
|
160
167
|
ret += aEl[v];
|
|
161
168
|
return ret;
|
|
162
|
-
},
|
|
169
|
+
}, "");
|
|
163
170
|
}
|
|
164
171
|
|
|
165
172
|
/**
|
|
@@ -169,8 +176,8 @@ export function getDomain(url: string, rules = ['hostname']): string {
|
|
|
169
176
|
* @returns {string} 'a-b-c'
|
|
170
177
|
*/
|
|
171
178
|
export function camelCaseToKebabCase(camelCase: string): string {
|
|
172
|
-
const kebabCase = camelCase.replace(/([A-Z])/g,
|
|
173
|
-
return kebabCase[0] ===
|
|
179
|
+
const kebabCase = camelCase.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
180
|
+
return kebabCase[0] === "-" ? kebabCase.substr(1) : kebabCase;
|
|
174
181
|
}
|
|
175
182
|
|
|
176
183
|
/**
|
|
@@ -180,8 +187,8 @@ export function camelCaseToKebabCase(camelCase: string): string {
|
|
|
180
187
|
* @returns {string} 'a_b_c'
|
|
181
188
|
*/
|
|
182
189
|
export function camelCase2Underscore(camelCase: string): string {
|
|
183
|
-
const kebabCase = camelCase.replace(/([A-Z])/g,
|
|
184
|
-
return kebabCase[0] ===
|
|
190
|
+
const kebabCase = camelCase.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
191
|
+
return kebabCase[0] === "_" ? kebabCase.substr(1) : kebabCase;
|
|
185
192
|
}
|
|
186
193
|
|
|
187
194
|
/**
|
|
@@ -191,7 +198,7 @@ export function camelCase2Underscore(camelCase: string): string {
|
|
|
191
198
|
* @returns {string} Trimmed string.
|
|
192
199
|
*/
|
|
193
200
|
export function mTrim(str: string): string {
|
|
194
|
-
str = str.replace(/^\s+/,
|
|
201
|
+
str = str.replace(/^\s+/, ""); // 去除头部空格
|
|
195
202
|
let end = str.length - 1;
|
|
196
203
|
const ws = /\s/;
|
|
197
204
|
while (ws.test(str.charAt(end))) {
|
|
@@ -208,10 +215,10 @@ export function mTrim(str: string): string {
|
|
|
208
215
|
*/
|
|
209
216
|
export function newLine(str: string): string {
|
|
210
217
|
if (!str) {
|
|
211
|
-
return
|
|
218
|
+
return "";
|
|
212
219
|
}
|
|
213
|
-
const reg = new RegExp(
|
|
214
|
-
return str.replace(reg,
|
|
220
|
+
const reg = new RegExp("\\n", "g");
|
|
221
|
+
return str.replace(reg, "<br />");
|
|
215
222
|
}
|
|
216
223
|
|
|
217
224
|
/**
|
|
@@ -232,7 +239,7 @@ export function deepCopyObject(obj: any): any {
|
|
|
232
239
|
*/
|
|
233
240
|
export function isJsonString(str: string): boolean {
|
|
234
241
|
try {
|
|
235
|
-
if (typeof JSON.parse(str) ===
|
|
242
|
+
if (typeof JSON.parse(str) === "object") {
|
|
236
243
|
return true;
|
|
237
244
|
}
|
|
238
245
|
} catch (e) {
|
|
@@ -248,7 +255,7 @@ export function isJsonString(str: string): boolean {
|
|
|
248
255
|
* @returns {string} Return the random string.
|
|
249
256
|
*/
|
|
250
257
|
export function generateRndNum(n = 5): string {
|
|
251
|
-
let ret =
|
|
258
|
+
let ret = "";
|
|
252
259
|
while (n--) {
|
|
253
260
|
ret += Math.floor(Math.random() * 10);
|
|
254
261
|
}
|
|
@@ -272,7 +279,7 @@ export function generateUniqueNum(n = 3): string {
|
|
|
272
279
|
* @param {number} fixSize 保留几位浮点数
|
|
273
280
|
*/
|
|
274
281
|
export function floatToPercent(num: number, fixSize = 0): string {
|
|
275
|
-
let ret =
|
|
282
|
+
let ret = "";
|
|
276
283
|
if (fixSize) {
|
|
277
284
|
ret = (num * 100).toFixed(fixSize);
|
|
278
285
|
} else {
|
|
@@ -323,10 +330,10 @@ export function hasClass(obj: any, cls: string): boolean {
|
|
|
323
330
|
*/
|
|
324
331
|
export function addClass(obj: any, cls: string): void {
|
|
325
332
|
const oriCls = obj.className;
|
|
326
|
-
let space =
|
|
327
|
-
let newCls =
|
|
328
|
-
if (oriCls !==
|
|
329
|
-
space =
|
|
333
|
+
let space = "";
|
|
334
|
+
let newCls = ""; // 获取对象的class值
|
|
335
|
+
if (oriCls !== "") {
|
|
336
|
+
space = " "; // 若原来的class不为空,跟一个空格
|
|
330
337
|
}
|
|
331
338
|
newCls = oriCls + space + cls; // 将新的class加进去
|
|
332
339
|
obj.className = newCls; // 替换新class
|
|
@@ -338,25 +345,26 @@ export function addClass(obj: any, cls: string): void {
|
|
|
338
345
|
export function removeClass(obj: any, cls: string): void {
|
|
339
346
|
const oriCls = obj.className;
|
|
340
347
|
let newCls; // 获取对象的class值
|
|
341
|
-
newCls =
|
|
342
|
-
newCls = newCls.replace(/(\s+)/gi,
|
|
343
|
-
newCls = newCls.replace(
|
|
344
|
-
newCls = newCls.replace(/(^\s+)|(\s+$)/g,
|
|
348
|
+
newCls = " " + oriCls + " "; // 前后加空格
|
|
349
|
+
newCls = newCls.replace(/(\s+)/gi, " "); // 将多余的空格替换成一个空格
|
|
350
|
+
newCls = newCls.replace(" " + cls + " ", " "); // 将加了前后空格的cls替换成空格' '
|
|
351
|
+
newCls = newCls.replace(/(^\s+)|(\s+$)/g, ""); // 去掉前后空格
|
|
345
352
|
obj.className = newCls;
|
|
346
353
|
}
|
|
347
354
|
|
|
348
355
|
/**
|
|
349
356
|
* EN: Throttle
|
|
350
|
-
*
|
|
357
|
+
*
|
|
351
358
|
* ZH: 节流
|
|
352
|
-
*
|
|
359
|
+
*
|
|
353
360
|
* Reference: [Lodash](https://lodash.com/docs/4.17.15#throttle)
|
|
354
361
|
*/
|
|
355
|
-
export function throttle(
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
362
|
+
export function throttle(
|
|
363
|
+
func: any,
|
|
364
|
+
wait: number,
|
|
365
|
+
options: { leading?: boolean; trailing?: boolean } = {}
|
|
366
|
+
): any {
|
|
367
|
+
options = Object.assign({}, options);
|
|
360
368
|
// timeout: setTimeout Handle
|
|
361
369
|
// previous: 上次时间戳
|
|
362
370
|
let context: any = null;
|
|
@@ -366,7 +374,7 @@ export function throttle(func: any, wait: number, options: { leading?: boolean;
|
|
|
366
374
|
// if (!options) {
|
|
367
375
|
// options = {};
|
|
368
376
|
// }
|
|
369
|
-
const later = function
|
|
377
|
+
const later = function() {
|
|
370
378
|
previous = options.leading === false ? 0 : mNow();
|
|
371
379
|
timeout = null;
|
|
372
380
|
result = func.apply(context, args);
|
|
@@ -374,7 +382,7 @@ export function throttle(func: any, wait: number, options: { leading?: boolean;
|
|
|
374
382
|
context = args = null;
|
|
375
383
|
}
|
|
376
384
|
};
|
|
377
|
-
return function
|
|
385
|
+
return function(...argRest: Array<any>) {
|
|
378
386
|
const now = mNow();
|
|
379
387
|
if (!previous && options.leading === false) {
|
|
380
388
|
previous = now;
|
|
@@ -401,11 +409,11 @@ export function throttle(func: any, wait: number, options: { leading?: boolean;
|
|
|
401
409
|
|
|
402
410
|
/**
|
|
403
411
|
* EN: Debounce
|
|
404
|
-
*
|
|
412
|
+
*
|
|
405
413
|
* ZH: 去抖
|
|
406
|
-
*
|
|
414
|
+
*
|
|
407
415
|
* Usage:
|
|
408
|
-
*
|
|
416
|
+
*
|
|
409
417
|
* ```
|
|
410
418
|
* const foo = debounce(() => {
|
|
411
419
|
* console.log('The debounced function will only be invoked in 1000 milliseconds, the other invoking will disappear during the wait time.');
|
|
@@ -418,7 +426,7 @@ export function debounce(func: any, wait: number, immediate?: any): any {
|
|
|
418
426
|
let timestamp: any = null;
|
|
419
427
|
let args: any = null;
|
|
420
428
|
let [result] = [null];
|
|
421
|
-
const later = function
|
|
429
|
+
const later = function() {
|
|
422
430
|
const last = mNow() - timestamp;
|
|
423
431
|
if (last < wait && last >= 0) {
|
|
424
432
|
timeout = setTimeout(later, wait - last);
|
|
@@ -432,7 +440,7 @@ export function debounce(func: any, wait: number, immediate?: any): any {
|
|
|
432
440
|
}
|
|
433
441
|
}
|
|
434
442
|
};
|
|
435
|
-
return function
|
|
443
|
+
return function(...argRest: Array<any>) {
|
|
436
444
|
context = this;
|
|
437
445
|
args = argRest;
|
|
438
446
|
timestamp = mNow();
|
|
@@ -456,12 +464,16 @@ export function debounce(func: any, wait: number, immediate?: any): any {
|
|
|
456
464
|
* @param {string} options.type 返回类型 d: 2(天) text: 2 天 4 时...
|
|
457
465
|
* @returns {String/number} 取决于 type
|
|
458
466
|
*/
|
|
459
|
-
export function friendlyInterval(
|
|
467
|
+
export function friendlyInterval(
|
|
468
|
+
start = 0,
|
|
469
|
+
end = 0,
|
|
470
|
+
options: { type?: string } = { type: "d" }
|
|
471
|
+
): number | string {
|
|
460
472
|
const { type } = options;
|
|
461
473
|
if (!isNumber(start)) start = new Date(start).getTime();
|
|
462
474
|
if (!isNumber(end)) end = new Date(end).getTime();
|
|
463
475
|
const t = end - start;
|
|
464
|
-
let ret =
|
|
476
|
+
let ret = "";
|
|
465
477
|
let [d, h, m, s] = new Array(4).fill(0);
|
|
466
478
|
if (t >= 0) {
|
|
467
479
|
d = Math.floor(t / 1000 / 60 / 60 / 24);
|
|
@@ -469,15 +481,15 @@ export function friendlyInterval(start = 0, end = 0, options: { type?: string; }
|
|
|
469
481
|
m = Math.floor(t / 1000 / 60);
|
|
470
482
|
s = Math.floor(t / 1000);
|
|
471
483
|
switch (type) {
|
|
472
|
-
case
|
|
484
|
+
case "d":
|
|
473
485
|
ret = d;
|
|
474
486
|
break;
|
|
475
|
-
case
|
|
487
|
+
case "text":
|
|
476
488
|
d = Math.floor(t / 1000 / 60 / 60 / 24);
|
|
477
489
|
h = Math.floor((t / 1000 / 60 / 60) % 24);
|
|
478
490
|
m = Math.floor((t / 1000 / 60) % 60);
|
|
479
491
|
s = Math.floor((t / 1000) % 60);
|
|
480
|
-
ret = d +
|
|
492
|
+
ret = d + " 天 " + h + " 时 " + m + " 分 " + s + " 秒";
|
|
481
493
|
break;
|
|
482
494
|
default:
|
|
483
495
|
ret = s;
|
|
@@ -494,14 +506,20 @@ export function friendlyInterval(start = 0, end = 0, options: { type?: string; }
|
|
|
494
506
|
* @param {boolean} options.isUnFiniteAsNumber 是否 无限 算数字(默认不算)
|
|
495
507
|
* @returns {boolean} true 是数字
|
|
496
508
|
*/
|
|
497
|
-
export function isNumber(
|
|
509
|
+
export function isNumber(
|
|
510
|
+
num: any,
|
|
511
|
+
options: { isNaNAsNumber?: boolean; isUnFiniteAsNumber?: boolean } = {
|
|
512
|
+
isNaNAsNumber: false,
|
|
513
|
+
isUnFiniteAsNumber: false
|
|
514
|
+
}
|
|
515
|
+
): boolean {
|
|
498
516
|
const { isNaNAsNumber, isUnFiniteAsNumber } = Object.assign(
|
|
499
517
|
{ isNaNAsNumber: false, isUnFiniteAsNumber: false },
|
|
500
|
-
options
|
|
518
|
+
options
|
|
501
519
|
);
|
|
502
520
|
let ret = true;
|
|
503
521
|
// 数字类型
|
|
504
|
-
if (typeof num !==
|
|
522
|
+
if (typeof num !== "number") {
|
|
505
523
|
ret = false;
|
|
506
524
|
}
|
|
507
525
|
// 无限值
|
|
@@ -524,7 +542,7 @@ export function isNumber(num: any, options: { isNaNAsNumber?: boolean; isUnFinit
|
|
|
524
542
|
*/
|
|
525
543
|
export function doFn(fn: any, ...params: any[]): any {
|
|
526
544
|
let ret = null;
|
|
527
|
-
if (fn && typeof fn ===
|
|
545
|
+
if (fn && typeof fn === "function") {
|
|
528
546
|
ret = fn(...params);
|
|
529
547
|
}
|
|
530
548
|
return ret;
|
|
@@ -595,35 +613,42 @@ export function getLocalStorage(key: string): any {
|
|
|
595
613
|
* @param {string} options.id -- link标签id
|
|
596
614
|
* @returns {Promise<boolean>} true -- 加载成功
|
|
597
615
|
*/
|
|
598
|
-
export function loadCSS(
|
|
616
|
+
export function loadCSS(
|
|
617
|
+
url: string,
|
|
618
|
+
options: { id?: string } = { id: "" }
|
|
619
|
+
): Promise<boolean | Error | any> {
|
|
599
620
|
const { id } = options;
|
|
600
621
|
let success: (v: boolean) => void;
|
|
601
622
|
let fail: (v: Error) => void;
|
|
602
623
|
const status = new Promise((resolve, reject) => {
|
|
603
|
-
|
|
624
|
+
[success, fail] = [resolve, reject];
|
|
604
625
|
});
|
|
605
626
|
// const tempCB = (typeof callback === 'function' ? callback : function () { });
|
|
606
|
-
const callback = function
|
|
627
|
+
const callback = function() {
|
|
607
628
|
// doFn(success, true);
|
|
608
629
|
success(true);
|
|
609
630
|
};
|
|
610
|
-
let node: any = document.createElement(
|
|
611
|
-
const supportOnload =
|
|
612
|
-
const isOldWebKit =
|
|
631
|
+
let node: any = document.createElement("link");
|
|
632
|
+
const supportOnload = "onload" in node;
|
|
633
|
+
const isOldWebKit =
|
|
634
|
+
+navigator.userAgent.replace(
|
|
635
|
+
/.*(?:AppleWebKit|AndroidWebKit)\/?(\d+).*/i,
|
|
636
|
+
"$1"
|
|
637
|
+
) < 536; // webkit旧内核做特殊处理
|
|
613
638
|
const protectNum = 300000; // 阈值10分钟,一秒钟执行pollCss 500次
|
|
614
639
|
|
|
615
|
-
node.rel =
|
|
616
|
-
node.type =
|
|
640
|
+
node.rel = "stylesheet";
|
|
641
|
+
node.type = "text/css";
|
|
617
642
|
node.href = url;
|
|
618
|
-
if (typeof id !==
|
|
643
|
+
if (typeof id !== "undefined") {
|
|
619
644
|
node.id = id;
|
|
620
645
|
}
|
|
621
|
-
document.getElementsByTagName(
|
|
646
|
+
document.getElementsByTagName("head")[0].appendChild(node);
|
|
622
647
|
|
|
623
648
|
// for Old WebKit and Old Firefox
|
|
624
649
|
if (isOldWebKit || !supportOnload) {
|
|
625
650
|
// Begin after node insertion
|
|
626
|
-
setTimeout(function
|
|
651
|
+
setTimeout(function() {
|
|
627
652
|
pollCss(node, callback, 0);
|
|
628
653
|
}, 1);
|
|
629
654
|
return status;
|
|
@@ -631,13 +656,13 @@ export function loadCSS(url: string, options: { id?: string } = { id: '' }): Pro
|
|
|
631
656
|
|
|
632
657
|
if (supportOnload) {
|
|
633
658
|
node.onload = onload;
|
|
634
|
-
node.onerror = function
|
|
659
|
+
node.onerror = function() {
|
|
635
660
|
// 加载失败(404)
|
|
636
661
|
onload();
|
|
637
662
|
};
|
|
638
663
|
} else {
|
|
639
664
|
// todo: 和 !supportOnload 重复
|
|
640
|
-
node.onreadystatechange = function
|
|
665
|
+
node.onreadystatechange = function() {
|
|
641
666
|
if (/loaded|complete/.test(node.readyState)) {
|
|
642
667
|
onload();
|
|
643
668
|
}
|
|
@@ -693,13 +718,13 @@ export function loadCSS(url: string, options: { id?: string } = { id: '' }): Pro
|
|
|
693
718
|
// The value of `ex.name` is changed from "NS_ERROR_DOM_SECURITY_ERR"
|
|
694
719
|
// to "SecurityError" since Firefox 13.0. But Firefox is less than 9.0
|
|
695
720
|
// in here, So it is ok to just rely on "NS_ERROR_DOM_SECURITY_ERR"
|
|
696
|
-
if ((ex as any).name ===
|
|
721
|
+
if ((ex as any).name === "NS_ERROR_DOM_SECURITY_ERR") {
|
|
697
722
|
isLoaded = true;
|
|
698
723
|
}
|
|
699
724
|
}
|
|
700
725
|
}
|
|
701
726
|
|
|
702
|
-
setTimeout(function
|
|
727
|
+
setTimeout(function() {
|
|
703
728
|
if (isLoaded) {
|
|
704
729
|
// 延迟20ms是为了给下载的样式留够渲染的时间
|
|
705
730
|
callback();
|
|
@@ -721,32 +746,49 @@ export function loadCSS(url: string, options: { id?: string } = { id: '' }): Pro
|
|
|
721
746
|
* @param {boolean} options.isDefer -- 是否添加 defer 标签
|
|
722
747
|
* @returns {Promise<boolean>} -- true 成功
|
|
723
748
|
*/
|
|
724
|
-
export function loadScript(
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
749
|
+
export function loadScript(
|
|
750
|
+
url: string,
|
|
751
|
+
options: {
|
|
752
|
+
id: string;
|
|
753
|
+
callback: (...params: any[]) => any;
|
|
754
|
+
timeout: number;
|
|
755
|
+
isDefer: boolean;
|
|
756
|
+
} = {
|
|
757
|
+
id: "",
|
|
758
|
+
callback: function() {
|
|
759
|
+
/* pass */
|
|
760
|
+
},
|
|
761
|
+
timeout: 5000,
|
|
762
|
+
isDefer: false
|
|
763
|
+
}
|
|
764
|
+
): Promise<boolean | string | Error> {
|
|
730
765
|
const { id, callback, timeout, isDefer } = Object.assign(
|
|
731
|
-
{
|
|
732
|
-
|
|
766
|
+
{
|
|
767
|
+
id: "",
|
|
768
|
+
callback: function() {
|
|
769
|
+
/* pass */
|
|
770
|
+
},
|
|
771
|
+
timeout: 5000,
|
|
772
|
+
isDefer: false
|
|
773
|
+
},
|
|
774
|
+
options
|
|
733
775
|
);
|
|
734
776
|
let success: any = null;
|
|
735
777
|
let fail: any = null;
|
|
736
|
-
const script: any = document.createElement(
|
|
778
|
+
const script: any = document.createElement("script");
|
|
737
779
|
// 如果没有 script 标签,那么代码就不会运行。可以利用这一事实,在页面的第一个 script 标签上使用 insertBefore()。
|
|
738
|
-
const firstScript: any = document.getElementsByTagName(
|
|
739
|
-
script.type =
|
|
780
|
+
const firstScript: any = document.getElementsByTagName("script")[0];
|
|
781
|
+
script.type = "text/javascript";
|
|
740
782
|
if (isDefer) {
|
|
741
|
-
script.defer =
|
|
783
|
+
script.defer = "defer";
|
|
742
784
|
}
|
|
743
785
|
if (id) {
|
|
744
786
|
script.id = id;
|
|
745
787
|
}
|
|
746
788
|
if (script.readyState) {
|
|
747
789
|
// IE
|
|
748
|
-
script.onreadystatechange = function
|
|
749
|
-
if (script.readyState ===
|
|
790
|
+
script.onreadystatechange = function() {
|
|
791
|
+
if (script.readyState === "loaded" || script.readyState === "complete") {
|
|
750
792
|
script.onreadystatechange = null;
|
|
751
793
|
doFn(callback);
|
|
752
794
|
doFn(success, true);
|
|
@@ -754,7 +796,7 @@ export function loadScript(url: string, options: {
|
|
|
754
796
|
};
|
|
755
797
|
} else {
|
|
756
798
|
// Others
|
|
757
|
-
script.onload = function
|
|
799
|
+
script.onload = function() {
|
|
758
800
|
doFn(callback);
|
|
759
801
|
doFn(success, true);
|
|
760
802
|
};
|
|
@@ -762,9 +804,9 @@ export function loadScript(url: string, options: {
|
|
|
762
804
|
script.src = url;
|
|
763
805
|
firstScript && firstScript.parentNode.insertBefore(script, firstScript);
|
|
764
806
|
return new Promise((resolve, reject) => {
|
|
765
|
-
|
|
807
|
+
[success, fail] = [resolve, reject];
|
|
766
808
|
if (timeout) {
|
|
767
|
-
setTimeout(fail.bind(null, Error(
|
|
809
|
+
setTimeout(fail.bind(null, Error("timeout")), timeout);
|
|
768
810
|
}
|
|
769
811
|
});
|
|
770
812
|
}
|
|
@@ -787,18 +829,23 @@ export function mNow(): number {
|
|
|
787
829
|
* @method setCookie
|
|
788
830
|
* @description 设置 Cookie
|
|
789
831
|
*/
|
|
790
|
-
export function setCookie(
|
|
832
|
+
export function setCookie(
|
|
833
|
+
name: string,
|
|
834
|
+
value: string,
|
|
835
|
+
days: number,
|
|
836
|
+
domain: string
|
|
837
|
+
): void {
|
|
791
838
|
let domainParts, expires;
|
|
792
839
|
let date: any;
|
|
793
840
|
if (days) {
|
|
794
841
|
date = new Date();
|
|
795
|
-
date.setTime(date.getTime() +
|
|
842
|
+
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
|
796
843
|
expires = "; expires=" + date.toGMTString();
|
|
797
844
|
} else {
|
|
798
845
|
expires = "";
|
|
799
846
|
}
|
|
800
847
|
const host = location.host;
|
|
801
|
-
if (host.split(
|
|
848
|
+
if (host.split(".").length === 1) {
|
|
802
849
|
// no "." in a domain - it's localhost or something similar
|
|
803
850
|
document.cookie = name + "=" + value + expires + "; path=/";
|
|
804
851
|
} else {
|
|
@@ -811,16 +858,18 @@ export function setCookie(name: string, value: string, days: number, domain: str
|
|
|
811
858
|
// If the cookie will not be set, it means ".com"
|
|
812
859
|
// is a top level domain and we need to
|
|
813
860
|
// set the cookie to ".foo.com"
|
|
814
|
-
domainParts = host.split(
|
|
861
|
+
domainParts = host.split(".");
|
|
815
862
|
domainParts.shift();
|
|
816
|
-
domain = domain ||
|
|
817
|
-
document.cookie =
|
|
863
|
+
domain = domain || "." + domainParts.join(".");
|
|
864
|
+
document.cookie =
|
|
865
|
+
name + "=" + value + expires + "; path=/; domain=" + domain;
|
|
818
866
|
// check if cookie was successfuly set to the given domain
|
|
819
867
|
// (otherwise it was a Top-Level Domain)
|
|
820
868
|
if (getCookie(name) === null || getCookie(name) !== value) {
|
|
821
869
|
// append "." to current domain
|
|
822
|
-
domain = domain ||
|
|
823
|
-
document.cookie =
|
|
870
|
+
domain = domain || "." + host;
|
|
871
|
+
document.cookie =
|
|
872
|
+
name + "=" + value + expires + "; path=/; domain=" + domain;
|
|
824
873
|
}
|
|
825
874
|
}
|
|
826
875
|
}
|
|
@@ -831,15 +880,15 @@ export function setCookie(name: string, value: string, days: number, domain: str
|
|
|
831
880
|
*/
|
|
832
881
|
export function getCookie(name: string): string {
|
|
833
882
|
const nameEQ = name + "=";
|
|
834
|
-
const ca = document.cookie.split(
|
|
883
|
+
const ca = document.cookie.split(";");
|
|
835
884
|
for (let i = 0; i < ca.length; i++) {
|
|
836
885
|
let c = ca[i];
|
|
837
|
-
while (c.charAt(0) ==
|
|
886
|
+
while (c.charAt(0) == " ") {
|
|
838
887
|
c = c.substring(1, c.length);
|
|
839
888
|
}
|
|
840
889
|
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
|
841
890
|
}
|
|
842
|
-
return
|
|
891
|
+
return "";
|
|
843
892
|
}
|
|
844
893
|
|
|
845
894
|
interface WebPerformance {
|
|
@@ -852,18 +901,24 @@ interface WebPerformance {
|
|
|
852
901
|
* @param {boolean} camelCase -- true(默认) 以驼峰形式返回数据 false 以下划线形式返回数据
|
|
853
902
|
* @returns {Promise<object>} 加载数据
|
|
854
903
|
*/
|
|
855
|
-
export function getPerformance(
|
|
904
|
+
export function getPerformance(
|
|
905
|
+
camelCase = true
|
|
906
|
+
): Promise<WebPerformance | Error> {
|
|
856
907
|
let success: (v: WebPerformance) => void;
|
|
857
908
|
let fail: (v: Error) => void;
|
|
858
909
|
const status: Promise<WebPerformance> = new Promise((resolve, reject) => {
|
|
859
|
-
|
|
910
|
+
[success, fail] = [resolve, reject];
|
|
860
911
|
});
|
|
861
912
|
const timing = window.performance.timing;
|
|
862
913
|
const startTime = timing.navigationStart || timing.fetchStart;
|
|
863
914
|
let firstPaintTime: any;
|
|
864
915
|
let firstContentfulPaintTime: any;
|
|
865
916
|
// 是否已经形成数据(页面加载完成之后)
|
|
866
|
-
if (
|
|
917
|
+
if (
|
|
918
|
+
window.performance &&
|
|
919
|
+
window.performance.timing &&
|
|
920
|
+
window.performance.timing.loadEventEnd > 0
|
|
921
|
+
) {
|
|
867
922
|
// console.log('created')
|
|
868
923
|
getTiming();
|
|
869
924
|
} else {
|
|
@@ -881,16 +936,16 @@ export function getPerformance(camelCase = true): Promise<WebPerformance | Error
|
|
|
881
936
|
try {
|
|
882
937
|
if (window.performance && Boolean(window.performance.getEntriesByType)) {
|
|
883
938
|
const performance = window.performance;
|
|
884
|
-
const performanceEntries = performance.getEntriesByType(
|
|
939
|
+
const performanceEntries = performance.getEntriesByType("paint");
|
|
885
940
|
performanceEntries.forEach((performanceEntry, i, entries) => {
|
|
886
941
|
const startTime = Math.round(performanceEntry.startTime);
|
|
887
|
-
if (performanceEntry.name ===
|
|
942
|
+
if (performanceEntry.name === "first-paint")
|
|
888
943
|
firstPaintTime = startTime;
|
|
889
|
-
else if (performanceEntry.name ===
|
|
944
|
+
else if (performanceEntry.name === "first-contentful-paint")
|
|
890
945
|
firstContentfulPaintTime = startTime;
|
|
891
946
|
});
|
|
892
947
|
} else {
|
|
893
|
-
console.error(
|
|
948
|
+
console.error("paint");
|
|
894
949
|
}
|
|
895
950
|
} catch (e) {
|
|
896
951
|
console.error((e as any).message);
|
|
@@ -898,7 +953,7 @@ export function getPerformance(camelCase = true): Promise<WebPerformance | Error
|
|
|
898
953
|
// 获取加载时间
|
|
899
954
|
if (
|
|
900
955
|
window.performance &&
|
|
901
|
-
typeof window.performance.getEntries ===
|
|
956
|
+
typeof window.performance.getEntries === "function"
|
|
902
957
|
) {
|
|
903
958
|
const performanceNavigationTiming: any =
|
|
904
959
|
(window.performance.getEntries() || [])[0] || {};
|
|
@@ -923,8 +978,8 @@ export function getPerformance(camelCase = true): Promise<WebPerformance | Error
|
|
|
923
978
|
onloadTime: timing.loadEventStart - startTime || 0, //*onload时间(总和)
|
|
924
979
|
whiteTime: timing.responseStart - startTime, //*白屏时间
|
|
925
980
|
renderTime: timing.loadEventEnd - startTime || 0, //整个过程的时间之和
|
|
926
|
-
decodedBodySize: performanceNavigationTiming.decodedBodySize ||
|
|
927
|
-
encodedBodySize: performanceNavigationTiming.encodedBodySize ||
|
|
981
|
+
decodedBodySize: performanceNavigationTiming.decodedBodySize || "", //页面压缩前大小
|
|
982
|
+
encodedBodySize: performanceNavigationTiming.encodedBodySize || "" //页面压缩后大小
|
|
928
983
|
};
|
|
929
984
|
// 过滤异常数据
|
|
930
985
|
Object.keys(data).forEach(k => {
|
|
@@ -948,23 +1003,26 @@ export function getPerformance(camelCase = true): Promise<WebPerformance | Error
|
|
|
948
1003
|
}
|
|
949
1004
|
success(Underscore || data);
|
|
950
1005
|
} else {
|
|
951
|
-
fail(Error(
|
|
1006
|
+
fail(Error("startTime"));
|
|
952
1007
|
}
|
|
953
1008
|
} else {
|
|
954
|
-
fail(Error(
|
|
1009
|
+
fail(Error("getEntries"));
|
|
955
1010
|
}
|
|
956
1011
|
}
|
|
957
1012
|
//获取当前操作系统
|
|
958
1013
|
function getOS() {
|
|
959
1014
|
let os;
|
|
960
|
-
if (
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1015
|
+
if (
|
|
1016
|
+
navigator.userAgent.indexOf("Android") > -1 ||
|
|
1017
|
+
navigator.userAgent.indexOf("Linux") > -1
|
|
1018
|
+
) {
|
|
1019
|
+
os = "android";
|
|
1020
|
+
} else if (navigator.userAgent.indexOf("iPhone") > -1) {
|
|
1021
|
+
os = "ios";
|
|
1022
|
+
} else if (navigator.userAgent.indexOf("Windows Phone") > -1) {
|
|
1023
|
+
os = "wp";
|
|
966
1024
|
} else {
|
|
967
|
-
os =
|
|
1025
|
+
os = "others";
|
|
968
1026
|
}
|
|
969
1027
|
return os;
|
|
970
1028
|
}
|
|
@@ -972,13 +1030,16 @@ export function getPerformance(camelCase = true): Promise<WebPerformance | Error
|
|
|
972
1030
|
function getOSVersion() {
|
|
973
1031
|
let OSVision: any;
|
|
974
1032
|
const u = navigator.userAgent;
|
|
975
|
-
const isAndroid = u.indexOf(
|
|
1033
|
+
const isAndroid = u.indexOf("Android") > -1 || u.indexOf("Linux") > -1; //Android
|
|
976
1034
|
const isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
|
|
977
1035
|
if (isAndroid) {
|
|
978
|
-
OSVision = (navigator.userAgent.split(
|
|
1036
|
+
OSVision = (navigator.userAgent.split(";")[1].match(/\d+\.\d+/g) ||
|
|
1037
|
+
[])[0];
|
|
979
1038
|
}
|
|
980
1039
|
if (isIOS) {
|
|
981
|
-
OSVision = (navigator.userAgent
|
|
1040
|
+
OSVision = (navigator.userAgent
|
|
1041
|
+
.split(";")[1]
|
|
1042
|
+
.match(/(\d+)_(\d+)_?(\d+)?/) || [])[0];
|
|
982
1043
|
}
|
|
983
1044
|
return OSVision;
|
|
984
1045
|
}
|
|
@@ -986,20 +1047,39 @@ export function getPerformance(camelCase = true): Promise<WebPerformance | Error
|
|
|
986
1047
|
function getDeviceType() {
|
|
987
1048
|
let deviceType;
|
|
988
1049
|
const sUserAgent = navigator.userAgent.toLowerCase();
|
|
989
|
-
const bIsIpad = sUserAgent.match(/(ipad)/i) &&
|
|
990
|
-
const bIsIphoneOs = sUserAgent.match(/iphone os/i) &&
|
|
991
|
-
const bIsMidp = sUserAgent.match(/midp/i) &&
|
|
992
|
-
const bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) &&
|
|
993
|
-
const bIsUc = sUserAgent.match(/ucweb/i) &&
|
|
994
|
-
const bIsAndroid = sUserAgent.match(/android/i) &&
|
|
995
|
-
const bIsCE = sUserAgent.match(/windows ce/i) &&
|
|
996
|
-
const bIsWM = sUserAgent.match(/windows mobile/i) &&
|
|
997
|
-
if (
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1050
|
+
const bIsIpad = sUserAgent.match(/(ipad)/i) && "ipad";
|
|
1051
|
+
const bIsIphoneOs = sUserAgent.match(/iphone os/i) && "iphone os";
|
|
1052
|
+
const bIsMidp = sUserAgent.match(/midp/i) && "midp";
|
|
1053
|
+
const bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) && "rv:1.2.3.4";
|
|
1054
|
+
const bIsUc = sUserAgent.match(/ucweb/i) && "ucweb";
|
|
1055
|
+
const bIsAndroid = sUserAgent.match(/android/i) && "android";
|
|
1056
|
+
const bIsCE = sUserAgent.match(/windows ce/i) && "windows ce";
|
|
1057
|
+
const bIsWM = sUserAgent.match(/windows mobile/i) && "windows mobile";
|
|
1058
|
+
if (
|
|
1059
|
+
!(
|
|
1060
|
+
bIsIpad ||
|
|
1061
|
+
bIsIphoneOs ||
|
|
1062
|
+
bIsMidp ||
|
|
1063
|
+
bIsUc7 ||
|
|
1064
|
+
bIsUc ||
|
|
1065
|
+
bIsAndroid ||
|
|
1066
|
+
bIsCE ||
|
|
1067
|
+
bIsWM
|
|
1068
|
+
)
|
|
1069
|
+
) {
|
|
1070
|
+
deviceType = "pc"; //pc
|
|
1071
|
+
} else if (
|
|
1072
|
+
bIsIphoneOs ||
|
|
1073
|
+
bIsMidp ||
|
|
1074
|
+
bIsUc7 ||
|
|
1075
|
+
bIsUc ||
|
|
1076
|
+
bIsAndroid ||
|
|
1077
|
+
bIsCE ||
|
|
1078
|
+
bIsWM
|
|
1079
|
+
) {
|
|
1080
|
+
deviceType = "phone"; //phone
|
|
1001
1081
|
} else if (bIsIpad) {
|
|
1002
|
-
deviceType =
|
|
1082
|
+
deviceType = "ipad"; //ipad
|
|
1003
1083
|
} else {
|
|
1004
1084
|
deviceType = undefined;
|
|
1005
1085
|
}
|
|
@@ -1008,24 +1088,27 @@ export function getPerformance(camelCase = true): Promise<WebPerformance | Error
|
|
|
1008
1088
|
// 获取网络状态
|
|
1009
1089
|
function getNetWork() {
|
|
1010
1090
|
let netWork: any;
|
|
1011
|
-
if (
|
|
1091
|
+
if (
|
|
1092
|
+
(navigator as any).connection &&
|
|
1093
|
+
(navigator as any).connection.effectiveType
|
|
1094
|
+
) {
|
|
1012
1095
|
switch ((navigator as any).connection.effectiveType) {
|
|
1013
|
-
case
|
|
1014
|
-
netWork =
|
|
1096
|
+
case "wifi":
|
|
1097
|
+
netWork = "wifi"; // wifi
|
|
1015
1098
|
break;
|
|
1016
|
-
case
|
|
1017
|
-
netWork =
|
|
1099
|
+
case "4g":
|
|
1100
|
+
netWork = "4g"; // 4g
|
|
1018
1101
|
break;
|
|
1019
|
-
case
|
|
1020
|
-
netWork =
|
|
1102
|
+
case "2g":
|
|
1103
|
+
netWork = "2g"; // 2g
|
|
1021
1104
|
break;
|
|
1022
|
-
case
|
|
1023
|
-
netWork =
|
|
1105
|
+
case "3g":
|
|
1106
|
+
netWork = "3g"; // 3g
|
|
1024
1107
|
break;
|
|
1025
|
-
case
|
|
1026
|
-
netWork =
|
|
1108
|
+
case "ethernet":
|
|
1109
|
+
netWork = "ethernet"; // ethernet
|
|
1027
1110
|
break;
|
|
1028
|
-
case
|
|
1111
|
+
case "default":
|
|
1029
1112
|
netWork = undefined; // 未知
|
|
1030
1113
|
break;
|
|
1031
1114
|
}
|
|
@@ -1035,12 +1118,24 @@ export function getPerformance(camelCase = true): Promise<WebPerformance | Error
|
|
|
1035
1118
|
// 获取横竖屏状态
|
|
1036
1119
|
function getOrientationStatu() {
|
|
1037
1120
|
let orientationStatu: any;
|
|
1038
|
-
if (
|
|
1039
|
-
|
|
1040
|
-
|
|
1121
|
+
if (
|
|
1122
|
+
window.screen &&
|
|
1123
|
+
window.screen.orientation &&
|
|
1124
|
+
window.screen.orientation.angle
|
|
1125
|
+
) {
|
|
1126
|
+
if (
|
|
1127
|
+
window.screen.orientation.angle === 180 ||
|
|
1128
|
+
window.screen.orientation.angle === 0
|
|
1129
|
+
) {
|
|
1130
|
+
// 竖屏
|
|
1131
|
+
orientationStatu = "|";
|
|
1041
1132
|
}
|
|
1042
|
-
if (
|
|
1043
|
-
|
|
1133
|
+
if (
|
|
1134
|
+
window.screen.orientation.angle === 90 ||
|
|
1135
|
+
window.screen.orientation.angle === -90
|
|
1136
|
+
) {
|
|
1137
|
+
// 横屏
|
|
1138
|
+
orientationStatu = "-";
|
|
1044
1139
|
}
|
|
1045
1140
|
}
|
|
1046
1141
|
return orientationStatu;
|
|
@@ -1063,7 +1158,7 @@ export function getPerformance(camelCase = true): Promise<WebPerformance | Error
|
|
|
1063
1158
|
* @returns {boolean} true 命中
|
|
1064
1159
|
*/
|
|
1065
1160
|
export function inRate(rate: number): boolean {
|
|
1066
|
-
if(Math.random() < rate) {
|
|
1161
|
+
if (Math.random() < rate) {
|
|
1067
1162
|
return true;
|
|
1068
1163
|
}
|
|
1069
1164
|
return false;
|
|
@@ -1093,7 +1188,10 @@ export function isSafePWAEnv(): boolean {
|
|
|
1093
1188
|
}
|
|
1094
1189
|
// 判断是否支持 Promise
|
|
1095
1190
|
function isSupportPromise() {
|
|
1096
|
-
if
|
|
1191
|
+
if (
|
|
1192
|
+
typeof Promise !== "undefined" &&
|
|
1193
|
+
Promise.toString().indexOf("[native code]") !== -1
|
|
1194
|
+
) {
|
|
1097
1195
|
return true;
|
|
1098
1196
|
}
|
|
1099
1197
|
return false;
|
|
@@ -1101,13 +1199,13 @@ export function isSafePWAEnv(): boolean {
|
|
|
1101
1199
|
// 浏览器信息
|
|
1102
1200
|
const BrowserType = getBrowserInfo();
|
|
1103
1201
|
if (
|
|
1104
|
-
|
|
1202
|
+
"serviceWorker" in navigator &&
|
|
1105
1203
|
isSupportAsyncAwait() &&
|
|
1106
1204
|
isSupportPromise() &&
|
|
1107
1205
|
Boolean(window.fetch) &&
|
|
1108
1206
|
Boolean(window.indexedDB) &&
|
|
1109
1207
|
Boolean(window.caches) &&
|
|
1110
|
-
!BrowserType[
|
|
1208
|
+
!BrowserType["shell"]
|
|
1111
1209
|
) {
|
|
1112
1210
|
return true;
|
|
1113
1211
|
}
|
|
@@ -1116,13 +1214,13 @@ export function isSafePWAEnv(): boolean {
|
|
|
1116
1214
|
|
|
1117
1215
|
/**
|
|
1118
1216
|
* EN: Browser Information
|
|
1119
|
-
*
|
|
1217
|
+
*
|
|
1120
1218
|
* ZH: 返回浏览器信息 https://github.com/JowayYoung/juejin-code/blob/master/browser-type.js
|
|
1121
|
-
*
|
|
1219
|
+
*
|
|
1122
1220
|
* ```
|
|
1123
1221
|
* getBrowserInfo(); // {"engine":"webkit","engineVs":"537.36","platform":"desktop","supporter":"chrome","supporterVs":"85.0.4183.121","system":"windows","systemVs":"10"}
|
|
1124
1222
|
* ```
|
|
1125
|
-
*
|
|
1223
|
+
*
|
|
1126
1224
|
* | Index | Field | Description |
|
|
1127
1225
|
* | --- | --- | --- |
|
|
1128
1226
|
* | System | system | android, ios, windows, macos, linux |
|
|
@@ -1135,14 +1233,14 @@ export function isSafePWAEnv(): boolean {
|
|
|
1135
1233
|
* | Shell | shell | (Optional) wechat, qq_browser, qq_app, uc, 360, 2345, sougou, liebao, maxthon, bilibili |
|
|
1136
1234
|
* | Shell version | shellVs | (Optional) |
|
|
1137
1235
|
* | Apple device type | appleType | (Optional) iphone, ipad, ipod, iwatch |
|
|
1138
|
-
*
|
|
1236
|
+
*
|
|
1139
1237
|
* Example: Determine the environment of the mobile QQ.
|
|
1140
|
-
*
|
|
1238
|
+
*
|
|
1141
1239
|
* ```
|
|
1142
1240
|
* const { system, shell } = getBrowserInfo();
|
|
1143
1241
|
* const isMobileQQ = ['android', 'ios'].includes(system) && ['qq_browser', 'qq_app'].includes(shell);
|
|
1144
1242
|
* ```
|
|
1145
|
-
*
|
|
1243
|
+
*
|
|
1146
1244
|
* @returns 浏览器信息
|
|
1147
1245
|
*/
|
|
1148
1246
|
export function getBrowserInfo(): {
|
|
@@ -1163,7 +1261,7 @@ export function getBrowserInfo(): {
|
|
|
1163
1261
|
const testUa: (regexp: RegExp) => boolean = regexp => regexp.test(ua);
|
|
1164
1262
|
const testVs: (regexp: RegExp) => string = regexp => {
|
|
1165
1263
|
const matchRes = ua.match(regexp);
|
|
1166
|
-
let ret =
|
|
1264
|
+
let ret = "";
|
|
1167
1265
|
if (matchRes) {
|
|
1168
1266
|
ret = matchRes
|
|
1169
1267
|
.toString()
|
|
@@ -1173,9 +1271,9 @@ export function getBrowserInfo(): {
|
|
|
1173
1271
|
return ret;
|
|
1174
1272
|
};
|
|
1175
1273
|
// 系统
|
|
1176
|
-
let system =
|
|
1274
|
+
let system = "";
|
|
1177
1275
|
// Apple device type.
|
|
1178
|
-
let appleType =
|
|
1276
|
+
let appleType = "";
|
|
1179
1277
|
if (testUa(/windows|win32|win64|wow32|wow64/g)) {
|
|
1180
1278
|
system = "windows"; // windows系统
|
|
1181
1279
|
} else if (testUa(/macintosh|macintel/g)) {
|
|
@@ -1187,17 +1285,17 @@ export function getBrowserInfo(): {
|
|
|
1187
1285
|
} else if (testUa(/ios|iphone|ipad|ipod|iwatch/g)) {
|
|
1188
1286
|
system = "ios"; // ios系统
|
|
1189
1287
|
if (testUa(/iphone/g)) {
|
|
1190
|
-
appleType =
|
|
1288
|
+
appleType = "iphone";
|
|
1191
1289
|
} else if (testUa(/ipad/g)) {
|
|
1192
|
-
appleType =
|
|
1290
|
+
appleType = "ipad";
|
|
1193
1291
|
} else if (testUa(/iwatch/g)) {
|
|
1194
|
-
appleType =
|
|
1292
|
+
appleType = "iwatch";
|
|
1195
1293
|
} else if (testUa(/ipod/g)) {
|
|
1196
|
-
appleType =
|
|
1294
|
+
appleType = "ipod";
|
|
1197
1295
|
}
|
|
1198
1296
|
}
|
|
1199
1297
|
// 系统版本
|
|
1200
|
-
let systemVs =
|
|
1298
|
+
let systemVs = "";
|
|
1201
1299
|
if (system === "windows") {
|
|
1202
1300
|
if (testUa(/windows nt 5.0|windows 2000/g)) {
|
|
1203
1301
|
systemVs = "2000";
|
|
@@ -1224,15 +1322,15 @@ export function getBrowserInfo(): {
|
|
|
1224
1322
|
systemVs = testVs(/os [\d._]+/g);
|
|
1225
1323
|
}
|
|
1226
1324
|
// 平台
|
|
1227
|
-
let platform =
|
|
1325
|
+
let platform = "";
|
|
1228
1326
|
if (system === "windows" || system === "macos" || system === "linux") {
|
|
1229
1327
|
platform = "desktop"; // 桌面端
|
|
1230
1328
|
} else if (system === "android" || system === "ios" || testUa(/mobile/g)) {
|
|
1231
1329
|
platform = "mobile"; // 移动端
|
|
1232
1330
|
}
|
|
1233
1331
|
// 内核和载体
|
|
1234
|
-
let engine =
|
|
1235
|
-
let supporter =
|
|
1332
|
+
let engine = "";
|
|
1333
|
+
let supporter = "";
|
|
1236
1334
|
if (testUa(/applewebkit/g)) {
|
|
1237
1335
|
engine = "webkit"; // webkit内核
|
|
1238
1336
|
if (testUa(/edge/g)) {
|
|
@@ -1255,7 +1353,7 @@ export function getBrowserInfo(): {
|
|
|
1255
1353
|
supporter = "iexplore"; // iexplore浏览器
|
|
1256
1354
|
}
|
|
1257
1355
|
// 内核版本
|
|
1258
|
-
let engineVs =
|
|
1356
|
+
let engineVs = "";
|
|
1259
1357
|
if (engine === "webkit") {
|
|
1260
1358
|
engineVs = testVs(/applewebkit\/[\d._]+/g);
|
|
1261
1359
|
} else if (engine === "gecko") {
|
|
@@ -1266,7 +1364,7 @@ export function getBrowserInfo(): {
|
|
|
1266
1364
|
engineVs = testVs(/trident\/[\d._]+/g);
|
|
1267
1365
|
}
|
|
1268
1366
|
// 载体版本
|
|
1269
|
-
let supporterVs =
|
|
1367
|
+
let supporterVs = "";
|
|
1270
1368
|
if (supporter === "chrome") {
|
|
1271
1369
|
supporterVs = testVs(/chrome\/[\d._]+/g);
|
|
1272
1370
|
} else if (supporter === "safari") {
|
|
@@ -1281,8 +1379,8 @@ export function getBrowserInfo(): {
|
|
|
1281
1379
|
supporterVs = testVs(/edge\/[\d._]+/g);
|
|
1282
1380
|
}
|
|
1283
1381
|
// 外壳和外壳版本
|
|
1284
|
-
let shell =
|
|
1285
|
-
let shellVs =
|
|
1382
|
+
let shell = "";
|
|
1383
|
+
let shellVs = "";
|
|
1286
1384
|
if (testUa(/micromessenger/g)) {
|
|
1287
1385
|
shell = "wechat"; // 微信浏览器
|
|
1288
1386
|
shellVs = testVs(/micromessenger\/[\d._]+/g);
|
|
@@ -1309,29 +1407,32 @@ export function getBrowserInfo(): {
|
|
|
1309
1407
|
} else if (testUa(/biliapp/g)) {
|
|
1310
1408
|
shell = "bilibili"; // 哔哩哔哩
|
|
1311
1409
|
}
|
|
1312
|
-
return Object.assign(
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1410
|
+
return Object.assign(
|
|
1411
|
+
{
|
|
1412
|
+
engine, // webkit gecko presto trident
|
|
1413
|
+
engineVs,
|
|
1414
|
+
platform, // desktop mobile
|
|
1415
|
+
supporter, // chrome safari firefox opera iexplore edge
|
|
1416
|
+
supporterVs,
|
|
1417
|
+
system, // windows macos linux android ios
|
|
1418
|
+
systemVs
|
|
1419
|
+
},
|
|
1420
|
+
{
|
|
1421
|
+
shell, // wechat qq uc 360 2345 sougou liebao maxthon
|
|
1422
|
+
shellVs,
|
|
1423
|
+
appleType
|
|
1424
|
+
}
|
|
1425
|
+
);
|
|
1325
1426
|
} catch (err) {
|
|
1326
|
-
console.warn(
|
|
1427
|
+
console.warn("mazey:", err);
|
|
1327
1428
|
return {
|
|
1328
|
-
engine:
|
|
1329
|
-
engineVs:
|
|
1330
|
-
platform:
|
|
1331
|
-
supporter:
|
|
1332
|
-
supporterVs:
|
|
1333
|
-
system:
|
|
1334
|
-
systemVs:
|
|
1429
|
+
engine: "", // webkit gecko presto trident
|
|
1430
|
+
engineVs: "",
|
|
1431
|
+
platform: "", // desktop mobile
|
|
1432
|
+
supporter: "", // chrome safari firefox opera iexplore edge
|
|
1433
|
+
supporterVs: "",
|
|
1434
|
+
system: "", // windows macos linux android ios
|
|
1435
|
+
systemVs: ""
|
|
1335
1436
|
};
|
|
1336
1437
|
}
|
|
1337
1438
|
}
|
|
@@ -1342,8 +1443,8 @@ export function getBrowserInfo(): {
|
|
|
1342
1443
|
* @param {string} str 带html标签的字符串
|
|
1343
1444
|
* @returns {string} 字符串
|
|
1344
1445
|
*/
|
|
1345
|
-
export function clearHtml
|
|
1346
|
-
return str.replace(/<\/?.+?>/g,
|
|
1446
|
+
export function clearHtml(str: string): string {
|
|
1447
|
+
return str.replace(/<\/?.+?>/g, "").replace(/[\r\n]/g, "");
|
|
1347
1448
|
}
|
|
1348
1449
|
|
|
1349
1450
|
/**
|
|
@@ -1355,15 +1456,15 @@ export function clearHtml (str: string): string {
|
|
|
1355
1456
|
* @returnss {string} 返回截取后的字符串
|
|
1356
1457
|
*/
|
|
1357
1458
|
export function cutCHSString(str: string, len: number, hasDot = false): string {
|
|
1358
|
-
if (str ==
|
|
1359
|
-
return
|
|
1459
|
+
if (str == "" || !str) {
|
|
1460
|
+
return "";
|
|
1360
1461
|
} else {
|
|
1361
1462
|
let newLength = 0;
|
|
1362
|
-
let newStr =
|
|
1463
|
+
let newStr = "";
|
|
1363
1464
|
// eslint-disable-next-line no-control-regex
|
|
1364
1465
|
const chineseRegex = /[^\x00-\xff]/g;
|
|
1365
|
-
let singleChar =
|
|
1366
|
-
const strLength = str.replace(chineseRegex,
|
|
1466
|
+
let singleChar = "";
|
|
1467
|
+
const strLength = str.replace(chineseRegex, "**").length;
|
|
1367
1468
|
for (let i = 0; i < strLength; i++) {
|
|
1368
1469
|
singleChar = str.charAt(i).toString();
|
|
1369
1470
|
if (singleChar.match(chineseRegex) != null) {
|
|
@@ -1378,7 +1479,7 @@ export function cutCHSString(str: string, len: number, hasDot = false): string {
|
|
|
1378
1479
|
}
|
|
1379
1480
|
|
|
1380
1481
|
if (hasDot && strLength > len) {
|
|
1381
|
-
newStr +=
|
|
1482
|
+
newStr += "...";
|
|
1382
1483
|
}
|
|
1383
1484
|
return newStr;
|
|
1384
1485
|
}
|
|
@@ -1393,27 +1494,29 @@ export function cutCHSString(str: string, len: number, hasDot = false): string {
|
|
|
1393
1494
|
export function windowLoaded(timeout = 90): Promise<string | Error> {
|
|
1394
1495
|
let loaded: (value: string) => void = () => undefined;
|
|
1395
1496
|
let loadFail: (value: Error) => void;
|
|
1396
|
-
const status = new Promise(
|
|
1497
|
+
const status = new Promise(
|
|
1498
|
+
(resolve: (value: string) => void, reject: (value: Error) => void) => {
|
|
1397
1499
|
loaded = resolve;
|
|
1398
1500
|
loadFail = reject;
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1501
|
+
}
|
|
1502
|
+
);
|
|
1503
|
+
if (document.readyState === "complete") {
|
|
1504
|
+
loaded("complete");
|
|
1402
1505
|
} else {
|
|
1403
|
-
|
|
1506
|
+
window.addEventListener("load", () => loaded("load"));
|
|
1404
1507
|
}
|
|
1405
1508
|
// 超过 timeout 秒后加载失败
|
|
1406
|
-
setTimeout(() => loadFail(Error(
|
|
1509
|
+
setTimeout(() => loadFail(Error("timeout")), timeout * 1000);
|
|
1407
1510
|
return status;
|
|
1408
1511
|
}
|
|
1409
1512
|
|
|
1410
1513
|
/**
|
|
1411
1514
|
* EN: Add `<style>` in `<head>`.
|
|
1412
|
-
*
|
|
1515
|
+
*
|
|
1413
1516
|
* ZH: 添加样式标签; style: 样式标签内的字符串; id: `<style>` 标签的 `id`; 返回: 添加成功/失败.
|
|
1414
|
-
*
|
|
1517
|
+
*
|
|
1415
1518
|
* Example 1: Add the `<style>` with `id`, and repeated invoking will update the content instead of adding a new one.
|
|
1416
|
-
*
|
|
1519
|
+
*
|
|
1417
1520
|
* ```
|
|
1418
1521
|
* addStyle(
|
|
1419
1522
|
* `
|
|
@@ -1431,9 +1534,9 @@ export function windowLoaded(timeout = 90): Promise<string | Error> {
|
|
|
1431
1534
|
* // }
|
|
1432
1535
|
* // </style>
|
|
1433
1536
|
* ```
|
|
1434
|
-
*
|
|
1537
|
+
*
|
|
1435
1538
|
* Example 2: Add the `<style>` without `id`, and repeated invoking will adding a new one.
|
|
1436
|
-
*
|
|
1539
|
+
*
|
|
1437
1540
|
* ```
|
|
1438
1541
|
* addStyle(
|
|
1439
1542
|
* `
|
|
@@ -1448,12 +1551,15 @@ export function windowLoaded(timeout = 90): Promise<string | Error> {
|
|
|
1448
1551
|
* // }
|
|
1449
1552
|
* // </style>
|
|
1450
1553
|
* ```
|
|
1451
|
-
*
|
|
1554
|
+
*
|
|
1452
1555
|
* @param style Style string.
|
|
1453
1556
|
* @param options.id `id` in `<style>`
|
|
1454
1557
|
* @returns Success/Fail
|
|
1455
1558
|
*/
|
|
1456
|
-
export function addStyle(
|
|
1559
|
+
export function addStyle(
|
|
1560
|
+
style: string,
|
|
1561
|
+
options: { id?: string } = { id: "" }
|
|
1562
|
+
): boolean {
|
|
1457
1563
|
// console.log('_ style', style);
|
|
1458
1564
|
// console.log('_ options', options);
|
|
1459
1565
|
if (!style) {
|
|
@@ -1462,23 +1568,25 @@ export function addStyle(style: string, options: { id?: string; } = { id: '' }):
|
|
|
1462
1568
|
// 创建 style 文档碎片
|
|
1463
1569
|
const styleFrag = document.createDocumentFragment();
|
|
1464
1570
|
let idDom: HTMLElement | null = null;
|
|
1465
|
-
let domId =
|
|
1571
|
+
let domId = "";
|
|
1466
1572
|
// Custom Style
|
|
1467
|
-
const customStyle = document.createElement(
|
|
1573
|
+
const customStyle = document.createElement("style");
|
|
1468
1574
|
// 如果需要 ID
|
|
1469
1575
|
if (options.id) {
|
|
1470
1576
|
domId = `${options.id}`;
|
|
1471
1577
|
idDom = document.getElementById(domId);
|
|
1472
1578
|
// 如果 Dom 不存在,插入 style
|
|
1473
1579
|
if (!idDom) {
|
|
1474
|
-
customStyle.setAttribute(
|
|
1580
|
+
customStyle.setAttribute("id", options.id);
|
|
1475
1581
|
customStyle.innerHTML = style;
|
|
1476
1582
|
styleFrag.appendChild(customStyle);
|
|
1477
1583
|
document.head.appendChild(styleFrag);
|
|
1478
|
-
} else {
|
|
1584
|
+
} else {
|
|
1585
|
+
// 如果 Dom 存在,直接更新
|
|
1479
1586
|
idDom.innerHTML = style;
|
|
1480
1587
|
}
|
|
1481
|
-
} else {
|
|
1588
|
+
} else {
|
|
1589
|
+
// 不需要 ID,直接添加新标签
|
|
1482
1590
|
customStyle.innerHTML = style;
|
|
1483
1591
|
styleFrag.appendChild(customStyle);
|
|
1484
1592
|
document.head.appendChild(styleFrag);
|
|
@@ -1493,11 +1601,18 @@ export function addStyle(style: string, options: { id?: string; } = { id: '' }):
|
|
|
1493
1601
|
* @param {function} allowFn 允许打印的判断函数
|
|
1494
1602
|
* @returns {object} 新实例
|
|
1495
1603
|
*/
|
|
1496
|
-
export function genCustomConsole(
|
|
1497
|
-
|
|
1604
|
+
export function genCustomConsole(
|
|
1605
|
+
prefix = "",
|
|
1606
|
+
options: { isClose?: boolean } = { isClose: false }
|
|
1607
|
+
): Console {
|
|
1608
|
+
const { isClose } = Object.assign({ isClose: false }, options);
|
|
1609
|
+
const methods = ["log", "info", "warn", "error"];
|
|
1498
1610
|
const newConsole = Object.create(null);
|
|
1499
1611
|
methods.forEach(method => {
|
|
1500
|
-
newConsole[method] = function
|
|
1612
|
+
newConsole[method] = function(...argu: any) {
|
|
1613
|
+
if (isClose) {
|
|
1614
|
+
return false;
|
|
1615
|
+
}
|
|
1501
1616
|
if (prefix) {
|
|
1502
1617
|
(console as any)[method](prefix, ...argu);
|
|
1503
1618
|
} else {
|
|
@@ -1510,28 +1625,37 @@ export function genCustomConsole(prefix = ''): Console {
|
|
|
1510
1625
|
|
|
1511
1626
|
/**
|
|
1512
1627
|
* Verify the validity of axios response.
|
|
1513
|
-
*
|
|
1628
|
+
*
|
|
1514
1629
|
* Reference: [Handling Errors](https://axios-http.com/docs/handling_errors)
|
|
1515
1630
|
*/
|
|
1516
|
-
export function zAxiosIsValidRes(
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1631
|
+
export function zAxiosIsValidRes(
|
|
1632
|
+
res: any,
|
|
1633
|
+
options: {
|
|
1634
|
+
validStatusRange: number[];
|
|
1635
|
+
validCode: number[];
|
|
1636
|
+
} = {
|
|
1637
|
+
validStatusRange: [200, 300],
|
|
1638
|
+
validCode: [0]
|
|
1639
|
+
}
|
|
1640
|
+
): boolean {
|
|
1523
1641
|
const { validStatusRange, validCode } = Object.assign(
|
|
1524
1642
|
{
|
|
1525
1643
|
validStatusRange: [200, 300],
|
|
1526
|
-
validCode: [0]
|
|
1644
|
+
validCode: [0]
|
|
1527
1645
|
},
|
|
1528
|
-
options
|
|
1646
|
+
options
|
|
1529
1647
|
);
|
|
1530
1648
|
if (validStatusRange.length !== 2) {
|
|
1531
|
-
console.error(
|
|
1649
|
+
console.error("valid validStatusRange is required");
|
|
1532
1650
|
}
|
|
1533
1651
|
let ret = false;
|
|
1534
|
-
if (
|
|
1652
|
+
if (
|
|
1653
|
+
res &&
|
|
1654
|
+
res.status &&
|
|
1655
|
+
validStatusRange.length === 2 &&
|
|
1656
|
+
res.status >= validStatusRange[0] &&
|
|
1657
|
+
res.status < validStatusRange[1]
|
|
1658
|
+
) {
|
|
1535
1659
|
const resData = res.data;
|
|
1536
1660
|
if (resData && validCode.includes(resData.code)) {
|
|
1537
1661
|
ret = true;
|
|
@@ -1555,22 +1679,22 @@ export function isNonEmptyArray(arr: any[]): boolean {
|
|
|
1555
1679
|
* 语义化文件大小, 把字节转换成正常文件大小.
|
|
1556
1680
|
*/
|
|
1557
1681
|
export function getFileSize(size: number): string {
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1682
|
+
const toCeilStr: (v: number) => string = n => String(Math.ceil(n));
|
|
1683
|
+
if (!size) return "";
|
|
1684
|
+
const num = 1024.0; // byte
|
|
1685
|
+
if (size < num) {
|
|
1686
|
+
return size + " B";
|
|
1687
|
+
}
|
|
1688
|
+
if (size < Math.pow(num, 2)) {
|
|
1689
|
+
return toCeilStr(size / num) + " KB";
|
|
1690
|
+
} // kb
|
|
1691
|
+
if (size < Math.pow(num, 3)) {
|
|
1692
|
+
return toCeilStr(size / Math.pow(num, 2)) + " MB";
|
|
1693
|
+
} // M
|
|
1694
|
+
if (size < Math.pow(num, 4)) {
|
|
1695
|
+
return toCeilStr(size / Math.pow(num, 3)) + " G";
|
|
1696
|
+
} // G
|
|
1697
|
+
return toCeilStr(size / Math.pow(num, 4)) + " T";
|
|
1574
1698
|
}
|
|
1575
1699
|
|
|
1576
1700
|
/**
|
|
@@ -1580,16 +1704,17 @@ export function getFileSize(size: number): string {
|
|
|
1580
1704
|
*/
|
|
1581
1705
|
export function isSupportWebp(): Promise<boolean> {
|
|
1582
1706
|
const fn = (resolve: (v: boolean) => void) => {
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1707
|
+
const img = new Image();
|
|
1708
|
+
img.onload = () => {
|
|
1709
|
+
resolve(img.width > 0 && img.height > 0);
|
|
1710
|
+
};
|
|
1711
|
+
img.onerror = () => {
|
|
1712
|
+
resolve(false);
|
|
1713
|
+
};
|
|
1714
|
+
img.src =
|
|
1715
|
+
"data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=";
|
|
1716
|
+
};
|
|
1717
|
+
return new Promise(fn);
|
|
1593
1718
|
}
|
|
1594
1719
|
|
|
1595
1720
|
/**
|
|
@@ -1598,11 +1723,13 @@ export function isSupportWebp(): Promise<boolean> {
|
|
|
1598
1723
|
* Reference: [Generate a Hash from string in Javascript](https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery)
|
|
1599
1724
|
*/
|
|
1600
1725
|
export function genHashCode(str: string): number {
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1726
|
+
let hash = 0,
|
|
1727
|
+
i,
|
|
1728
|
+
chr;
|
|
1729
|
+
for (i = 0; i < str.length; i++) {
|
|
1730
|
+
chr = str.charCodeAt(i);
|
|
1731
|
+
hash = (hash << 5) - hash + chr;
|
|
1732
|
+
hash |= 0;
|
|
1733
|
+
}
|
|
1734
|
+
return hash;
|
|
1608
1735
|
}
|