pen-it 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/array/index.d.ts +0 -39
- package/dist/browser/index.d.ts +0 -29
- package/dist/control/index.d.ts +0 -8
- package/dist/cookie/index.d.ts +0 -7
- package/dist/copy/index.d.ts +0 -12
- package/dist/format/index.d.ts +0 -69
- package/dist/index.cjs +0 -294
- package/dist/index.js +0 -294
- package/dist/is/index.d.ts +0 -121
- package/dist/storage/index.d.ts +0 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,11 +3,6 @@
|
|
|
3
3
|
* 判断一个值是否为数组
|
|
4
4
|
* @param value - 要判断的值
|
|
5
5
|
* @returns 如果是数组返回 true,否则返回 false
|
|
6
|
-
* @example
|
|
7
|
-
* isArray([1, 2, 3])
|
|
8
|
-
* // => true
|
|
9
|
-
* isArray("hello")
|
|
10
|
-
* // => false
|
|
11
6
|
*/
|
|
12
7
|
const isArray = (value) => {
|
|
13
8
|
return Array.isArray(value);
|
|
@@ -16,11 +11,6 @@ const isArray = (value) => {
|
|
|
16
11
|
* 判断一个值是否为对象(但不是数组)
|
|
17
12
|
* @param value - 要判断的值
|
|
18
13
|
* @returns 如果是对象且不是数组返回 true,否则返回 false
|
|
19
|
-
* @example
|
|
20
|
-
* isObject({ a: 1 })
|
|
21
|
-
* // => true
|
|
22
|
-
* isObject([1, 2])
|
|
23
|
-
* // => false
|
|
24
14
|
*/
|
|
25
15
|
const isObject = (value) => {
|
|
26
16
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -30,9 +20,6 @@ const isObject = (value) => {
|
|
|
30
20
|
* @param val - 要判断的数据
|
|
31
21
|
* @param type - 数据类型字符串,如 "Array"、"Function"
|
|
32
22
|
* @returns 如果数据是指定类型返回 true
|
|
33
|
-
* @example
|
|
34
|
-
* is([], "Array")
|
|
35
|
-
* // => true
|
|
36
23
|
*/
|
|
37
24
|
const is = (val, type) => {
|
|
38
25
|
return Object.prototype.toString.call(val) === `[object ${type}]`;
|
|
@@ -41,9 +28,6 @@ const is = (val, type) => {
|
|
|
41
28
|
* 判断一个值是否为函数
|
|
42
29
|
* @param val - 要判断的数据
|
|
43
30
|
* @returns 如果是函数返回 true
|
|
44
|
-
* @example
|
|
45
|
-
* isFunction(() => {})
|
|
46
|
-
* // => true
|
|
47
31
|
*/
|
|
48
32
|
const isFunction = (val) => {
|
|
49
33
|
return is(val, "Function") || !!(val && val.constructor && val.call && val.apply);
|
|
@@ -52,9 +36,6 @@ const isFunction = (val) => {
|
|
|
52
36
|
* 判断一个值是否为 Date 对象
|
|
53
37
|
* @param val - 要判断的数据
|
|
54
38
|
* @returns 如果是 Date 对象返回 true
|
|
55
|
-
* @example
|
|
56
|
-
* isDate(new Date())
|
|
57
|
-
* // => true
|
|
58
39
|
*/
|
|
59
40
|
const isDate = (val) => {
|
|
60
41
|
return is(val, "Date") || !!val && val.constructor === Date;
|
|
@@ -63,11 +44,6 @@ const isDate = (val) => {
|
|
|
63
44
|
* 判断一个值是否为数字(NaN 和 Infinity 也视为数字)
|
|
64
45
|
* @param val - 要判断的数据
|
|
65
46
|
* @returns 如果是数字返回 true
|
|
66
|
-
* @example
|
|
67
|
-
* isNumber(42)
|
|
68
|
-
* // => true
|
|
69
|
-
* isNumber("42")
|
|
70
|
-
* // => false
|
|
71
47
|
*/
|
|
72
48
|
const isNumber = (val) => {
|
|
73
49
|
return Number(val) === val;
|
|
@@ -76,11 +52,6 @@ const isNumber = (val) => {
|
|
|
76
52
|
* 判断一个值是否为整数
|
|
77
53
|
* @param val - 要判断的数据
|
|
78
54
|
* @returns 如果是整数返回 true
|
|
79
|
-
* @example
|
|
80
|
-
* isInt(42)
|
|
81
|
-
* // => true
|
|
82
|
-
* isInt(3.14)
|
|
83
|
-
* // => false
|
|
84
55
|
*/
|
|
85
56
|
const isInt = (val) => {
|
|
86
57
|
return isNumber(val) && Number.isFinite(val) && val % 1 === 0;
|
|
@@ -89,11 +60,6 @@ const isInt = (val) => {
|
|
|
89
60
|
* 判断一个值是否为浮点数(有限小数)
|
|
90
61
|
* @param val - 要判断的数据
|
|
91
62
|
* @returns 如果是浮点数返回 true
|
|
92
|
-
* @example
|
|
93
|
-
* isFloat(3.14)
|
|
94
|
-
* // => true
|
|
95
|
-
* isFloat(42)
|
|
96
|
-
* // => false
|
|
97
63
|
*/
|
|
98
64
|
const isFloat = (val) => {
|
|
99
65
|
return isNumber(val) && Number.isFinite(val) && val % 1 !== 0;
|
|
@@ -102,9 +68,6 @@ const isFloat = (val) => {
|
|
|
102
68
|
* 判断一个值是否为异步函数
|
|
103
69
|
* @param val - 要判断的数据
|
|
104
70
|
* @returns 如果是异步函数返回 true
|
|
105
|
-
* @example
|
|
106
|
-
* isAsyncFunction(async () => {})
|
|
107
|
-
* // => true
|
|
108
71
|
*/
|
|
109
72
|
const isAsyncFunction = (val) => {
|
|
110
73
|
return is(val, "AsyncFunction");
|
|
@@ -113,9 +76,6 @@ const isAsyncFunction = (val) => {
|
|
|
113
76
|
* 判断一个值是否为 Promise
|
|
114
77
|
* @param value - 要判断的数据
|
|
115
78
|
* @returns 如果是 Promise 返回 true
|
|
116
|
-
* @example
|
|
117
|
-
* isPromise(Promise.resolve())
|
|
118
|
-
* // => true
|
|
119
79
|
*/
|
|
120
80
|
const isPromise = (value) => {
|
|
121
81
|
if (!value) return false;
|
|
@@ -127,11 +87,6 @@ const isPromise = (value) => {
|
|
|
127
87
|
* 判断一个值是否为字符串
|
|
128
88
|
* @param val - 要判断的数据
|
|
129
89
|
* @returns 如果是字符串返回 true
|
|
130
|
-
* @example
|
|
131
|
-
* isString("hello")
|
|
132
|
-
* // => true
|
|
133
|
-
* isString(42)
|
|
134
|
-
* // => false
|
|
135
90
|
*/
|
|
136
91
|
const isString = (val) => {
|
|
137
92
|
return is(val, "String") || typeof val === "string" || val instanceof String;
|
|
@@ -140,11 +95,6 @@ const isString = (val) => {
|
|
|
140
95
|
* 判断一个值是否为布尔值
|
|
141
96
|
* @param val - 要判断的数据
|
|
142
97
|
* @returns 如果是布尔值返回 true
|
|
143
|
-
* @example
|
|
144
|
-
* isBoolean(true)
|
|
145
|
-
* // => true
|
|
146
|
-
* isBoolean(1)
|
|
147
|
-
* // => false
|
|
148
98
|
*/
|
|
149
99
|
const isBoolean = (val) => {
|
|
150
100
|
return typeof val === "boolean" || is(val, "Boolean");
|
|
@@ -152,9 +102,6 @@ const isBoolean = (val) => {
|
|
|
152
102
|
/**
|
|
153
103
|
* 判断是否为 PC 端(浏览器环境)
|
|
154
104
|
* @returns 如果在浏览器环境中返回 true
|
|
155
|
-
* @example
|
|
156
|
-
* isPC()
|
|
157
|
-
* // => true(在浏览器中)
|
|
158
105
|
*/
|
|
159
106
|
const isPC = () => {
|
|
160
107
|
return typeof window !== "undefined";
|
|
@@ -163,9 +110,6 @@ const isPC = () => {
|
|
|
163
110
|
* 判断一个值是否为 window 对象
|
|
164
111
|
* @param val - 要判断的数据
|
|
165
112
|
* @returns 如果是 window 对象返回 true
|
|
166
|
-
* @example
|
|
167
|
-
* isWindow(window)
|
|
168
|
-
* // => true(在浏览器中)
|
|
169
113
|
*/
|
|
170
114
|
const isWindow = (val) => {
|
|
171
115
|
return typeof window !== "undefined" && is(val, "Window");
|
|
@@ -174,9 +118,6 @@ const isWindow = (val) => {
|
|
|
174
118
|
* 判断一个值是否为 DOM 元素
|
|
175
119
|
* @param val - 要判断的数据
|
|
176
120
|
* @returns 如果是 DOM 元素返回 true
|
|
177
|
-
* @example
|
|
178
|
-
* isElement(document.body)
|
|
179
|
-
* // => true
|
|
180
121
|
*/
|
|
181
122
|
const isElement = (val) => {
|
|
182
123
|
return isObject(val) && !!val.tagName;
|
|
@@ -185,9 +126,6 @@ const isElement = (val) => {
|
|
|
185
126
|
* 判断一个值是否为 null
|
|
186
127
|
* @param val - 要判断的数据
|
|
187
128
|
* @returns 如果是 null 返回 true
|
|
188
|
-
* @example
|
|
189
|
-
* isNull(null)
|
|
190
|
-
* // => true
|
|
191
129
|
*/
|
|
192
130
|
const isNull = (val) => {
|
|
193
131
|
return val === null;
|
|
@@ -196,11 +134,6 @@ const isNull = (val) => {
|
|
|
196
134
|
* 判断一个值是否为十六进制颜色
|
|
197
135
|
* @param str - 要判断的字符串
|
|
198
136
|
* @returns 如果是有效的十六进制颜色值返回 true
|
|
199
|
-
* @example
|
|
200
|
-
* isHexColor("#fff")
|
|
201
|
-
* // => true
|
|
202
|
-
* isHexColor("#ff0000")
|
|
203
|
-
* // => true
|
|
204
137
|
*/
|
|
205
138
|
const isHexColor = (str) => {
|
|
206
139
|
return /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(str);
|
|
@@ -208,9 +141,6 @@ const isHexColor = (str) => {
|
|
|
208
141
|
/**
|
|
209
142
|
* 判断设备是否为 iOS
|
|
210
143
|
* @returns 如果是 iOS 设备返回 true
|
|
211
|
-
* @example
|
|
212
|
-
* isIOS()
|
|
213
|
-
* // => true(在 iPhone/iPad 上)
|
|
214
144
|
*/
|
|
215
145
|
const isIOS = () => {
|
|
216
146
|
return /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
@@ -219,9 +149,6 @@ const isIOS = () => {
|
|
|
219
149
|
* 判断一个值是否为有效的电子邮件
|
|
220
150
|
* @param email - 要判断的字符串
|
|
221
151
|
* @returns 如果是有效的电子邮件地址返回 true
|
|
222
|
-
* @example
|
|
223
|
-
* isValidEmail("test@example.com")
|
|
224
|
-
* // => true
|
|
225
152
|
*/
|
|
226
153
|
const isValidEmail = (email) => {
|
|
227
154
|
return /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/.test(email);
|
|
@@ -230,11 +157,6 @@ const isValidEmail = (email) => {
|
|
|
230
157
|
* 判断一个值是否已定义(不是 undefined)
|
|
231
158
|
* @param val - 要判断的数据
|
|
232
159
|
* @returns 如果不是 undefined 返回 true
|
|
233
|
-
* @example
|
|
234
|
-
* isDef("hello")
|
|
235
|
-
* // => true
|
|
236
|
-
* isDef(undefined)
|
|
237
|
-
* // => false
|
|
238
160
|
*/
|
|
239
161
|
const isDef = (val) => {
|
|
240
162
|
return typeof val !== "undefined";
|
|
@@ -243,9 +165,6 @@ const isDef = (val) => {
|
|
|
243
165
|
* 判断一个值是否为 undefined
|
|
244
166
|
* @param val - 要判断的数据
|
|
245
167
|
* @returns 如果是 undefined 返回 true
|
|
246
|
-
* @example
|
|
247
|
-
* isUnDef(undefined)
|
|
248
|
-
* // => true
|
|
249
168
|
*/
|
|
250
169
|
const isUnDef = (val) => {
|
|
251
170
|
return typeof val === "undefined";
|
|
@@ -254,13 +173,6 @@ const isUnDef = (val) => {
|
|
|
254
173
|
* 判断一个值是否为 null 或 undefined
|
|
255
174
|
* @param val - 要判断的数据
|
|
256
175
|
* @returns 如果是 null 或 undefined 返回 true
|
|
257
|
-
* @example
|
|
258
|
-
* isNullOrUnDef(null)
|
|
259
|
-
* // => true
|
|
260
|
-
* isNullOrUnDef(undefined)
|
|
261
|
-
* // => true
|
|
262
|
-
* isNullOrUnDef("hello")
|
|
263
|
-
* // => false
|
|
264
176
|
*/
|
|
265
177
|
const isNullOrUnDef = (val) => {
|
|
266
178
|
return isUnDef(val) || isNull(val);
|
|
@@ -269,9 +181,6 @@ const isNullOrUnDef = (val) => {
|
|
|
269
181
|
* 判断一个值是否为 symbol
|
|
270
182
|
* @param value - 要判断的数据
|
|
271
183
|
* @returns 如果是 symbol 返回 true
|
|
272
|
-
* @example
|
|
273
|
-
* isSymbol(Symbol("foo"))
|
|
274
|
-
* // => true
|
|
275
184
|
*/
|
|
276
185
|
const isSymbol = (value) => {
|
|
277
186
|
return !!value && value.constructor === Symbol;
|
|
@@ -281,11 +190,6 @@ const isSymbol = (value) => {
|
|
|
281
190
|
* 原始类型包括:number、string、boolean、symbol、bigint、undefined、null
|
|
282
191
|
* @param value - 要判断的值
|
|
283
192
|
* @returns 如果是原始类型返回 true
|
|
284
|
-
* @example
|
|
285
|
-
* isPrimitive(42)
|
|
286
|
-
* // => true
|
|
287
|
-
* isPrimitive({})
|
|
288
|
-
* // => false
|
|
289
193
|
*/
|
|
290
194
|
const isPrimitive = (value) => {
|
|
291
195
|
return value === void 0 || value === null || typeof value !== "object" && typeof value !== "function";
|
|
@@ -295,13 +199,6 @@ const isPrimitive = (value) => {
|
|
|
295
199
|
* 空值包括:null、undefined、空字符串、空数组、空对象、空 Map/Set、无效 Date
|
|
296
200
|
* @param value - 要判断的数据
|
|
297
201
|
* @returns 如果为空返回 true
|
|
298
|
-
* @example
|
|
299
|
-
* isEmpty("")
|
|
300
|
-
* // => true
|
|
301
|
-
* isEmpty([])
|
|
302
|
-
* // => true
|
|
303
|
-
* isEmpty(0)
|
|
304
|
-
* // => false
|
|
305
202
|
*/
|
|
306
203
|
const isEmpty = (value) => {
|
|
307
204
|
if (value === null || value === void 0) return true;
|
|
@@ -319,19 +216,6 @@ const isEmpty = (value) => {
|
|
|
319
216
|
* 支持:字符串、数组、对象、Map、Set、类型化数组
|
|
320
217
|
* @param value - 要检查的值
|
|
321
218
|
* @returns 如果为空返回 true
|
|
322
|
-
* @example
|
|
323
|
-
* isEmptySv("")
|
|
324
|
-
* // => true
|
|
325
|
-
* isEmptySv(null)
|
|
326
|
-
* // => true
|
|
327
|
-
* isEmptySv([])
|
|
328
|
-
* // => true
|
|
329
|
-
* isEmptySv({})
|
|
330
|
-
* // => true
|
|
331
|
-
* isEmptySv(new Set())
|
|
332
|
-
* // => true
|
|
333
|
-
* isEmptySv(new Map())
|
|
334
|
-
* // => true
|
|
335
219
|
*/
|
|
336
220
|
function isEmptySv(value) {
|
|
337
221
|
if (value === null || value === void 0) return true;
|
|
@@ -346,11 +230,6 @@ function isEmptySv(value) {
|
|
|
346
230
|
* @param x - 要比较的第一个值
|
|
347
231
|
* @param y - 要比较的第二个值
|
|
348
232
|
* @returns 如果值深度相等返回 true
|
|
349
|
-
* @example
|
|
350
|
-
* isEqual({ a: 1 }, { a: 1 })
|
|
351
|
-
* // => true
|
|
352
|
-
* isEqual({ a: 1 }, { a: 2 })
|
|
353
|
-
* // => false
|
|
354
233
|
*/
|
|
355
234
|
const isEqual = (x, y) => {
|
|
356
235
|
if (Object.is(x, y)) return true;
|
|
@@ -372,9 +251,6 @@ const isEqual = (x, y) => {
|
|
|
372
251
|
* 完整日期时间(年/月/日 时分秒)_ 斜杠
|
|
373
252
|
* @param date - Date 对象
|
|
374
253
|
* @returns 格式化后的完整日期时间字符串,如 "2026/06/03 14:30:45"
|
|
375
|
-
* @example
|
|
376
|
-
* formatFull(new Date("2026-06-03T14:30:45"))
|
|
377
|
-
* // => "2026/06/03 14:30:45"
|
|
378
254
|
*/
|
|
379
255
|
const formatFull = (date) => {
|
|
380
256
|
return new Intl.DateTimeFormat("zh-CN", {
|
|
@@ -391,9 +267,6 @@ const formatFull = (date) => {
|
|
|
391
267
|
* 完整日期时间(年-月-日 时分秒)_ 短横线
|
|
392
268
|
* @param date - Date 对象
|
|
393
269
|
* @returns 格式化后的完整日期时间字符串,如 "2026-06-03 14:30:45"
|
|
394
|
-
* @example
|
|
395
|
-
* formatFullReplace(new Date("2026-06-03T14:30:45"))
|
|
396
|
-
* // => "2026-06-03 14:30:45"
|
|
397
270
|
*/
|
|
398
271
|
const formatFullReplace = (date) => {
|
|
399
272
|
return formatFull(date).replace(/\//g, "-");
|
|
@@ -402,9 +275,6 @@ const formatFullReplace = (date) => {
|
|
|
402
275
|
* 中文年月日
|
|
403
276
|
* @param date - Date 对象
|
|
404
277
|
* @returns 格式化后的中文日期字符串,如 "2026年6月3日"
|
|
405
|
-
* @example
|
|
406
|
-
* formatYMD(new Date("2026-06-03"))
|
|
407
|
-
* // => "2026年6月3日"
|
|
408
278
|
*/
|
|
409
279
|
const formatYMD = (date) => {
|
|
410
280
|
return new Intl.DateTimeFormat("zh-CN", {
|
|
@@ -417,9 +287,6 @@ const formatYMD = (date) => {
|
|
|
417
287
|
* 星期几
|
|
418
288
|
* @param date - Date 对象
|
|
419
289
|
* @returns 中文星期字符串,如 "星期三"
|
|
420
|
-
* @example
|
|
421
|
-
* formatWeek(new Date("2026-06-03"))
|
|
422
|
-
* // => "星期三"
|
|
423
290
|
*/
|
|
424
291
|
const formatWeek = (date) => {
|
|
425
292
|
return new Intl.DateTimeFormat("zh-CN", { weekday: "long" }).format(date);
|
|
@@ -429,9 +296,6 @@ const formatWeek = (date) => {
|
|
|
429
296
|
* @param value - 数值
|
|
430
297
|
* @param options - 格式化选项
|
|
431
298
|
* @returns 格式化后的货币字符串
|
|
432
|
-
* @example
|
|
433
|
-
* formatRmb(1234.56, { type: "zh-CN", currency: "CNY" })
|
|
434
|
-
* // => "¥1,234.56"
|
|
435
299
|
*/
|
|
436
300
|
const formatRmb = (value, options) => {
|
|
437
301
|
return new Intl.NumberFormat(options.type, {
|
|
@@ -443,9 +307,6 @@ const formatRmb = (value, options) => {
|
|
|
443
307
|
* 千位分隔符(数字格式化),中文(逗号分隔)
|
|
444
308
|
* @param value - 数值
|
|
445
309
|
* @returns 格式化后的千位分隔数字字符串
|
|
446
|
-
* @example
|
|
447
|
-
* formatNum(1234567)
|
|
448
|
-
* // => "1,234,567"
|
|
449
310
|
*/
|
|
450
311
|
const formatNum = (value) => {
|
|
451
312
|
return new Intl.NumberFormat("zh-CN").format(value);
|
|
@@ -455,9 +316,6 @@ const formatNum = (value) => {
|
|
|
455
316
|
* @param value - 百分比数值
|
|
456
317
|
* @param digit - 保留的小数位数,默认为 0
|
|
457
318
|
* @returns 格式化后的百分比字符串
|
|
458
|
-
* @example
|
|
459
|
-
* percentCN(0.1234, 2)
|
|
460
|
-
* // => "12.34%"
|
|
461
319
|
*/
|
|
462
320
|
const percentCN = (value, digit = 0) => {
|
|
463
321
|
return new Intl.NumberFormat("zh-CN", {
|
|
@@ -469,9 +327,6 @@ const percentCN = (value, digit = 0) => {
|
|
|
469
327
|
* 紧凑计数法(大数简化)_ 英文缩写
|
|
470
328
|
* @param value - 数值
|
|
471
329
|
* @returns 格式化后的紧凑数字字符串(英文缩写)
|
|
472
|
-
* @example
|
|
473
|
-
* compactEN(12345)
|
|
474
|
-
* // => "12K"
|
|
475
330
|
*/
|
|
476
331
|
const compactEN = (value) => {
|
|
477
332
|
return new Intl.NumberFormat("en-US", {
|
|
@@ -483,9 +338,6 @@ const compactEN = (value) => {
|
|
|
483
338
|
* 紧凑计数法(大数简化)_ 中文缩写
|
|
484
339
|
* @param value - 数值
|
|
485
340
|
* @returns 格式化后的紧凑数字字符串(中文缩写)
|
|
486
|
-
* @example
|
|
487
|
-
* compactCN(12345)
|
|
488
|
-
* // => "1.2万"
|
|
489
341
|
*/
|
|
490
342
|
const compactCN = (value) => {
|
|
491
343
|
return new Intl.NumberFormat("zh-CN", {
|
|
@@ -498,12 +350,6 @@ const compactCN = (value) => {
|
|
|
498
350
|
* @param value - 数值
|
|
499
351
|
* @param digit - 保留的小数位数,默认为 0
|
|
500
352
|
* @returns 格式化后的带正负号的数值显示
|
|
501
|
-
* @example
|
|
502
|
-
* signed(42, 1)
|
|
503
|
-
* // => "+42.0"
|
|
504
|
-
* @example
|
|
505
|
-
* signed(-5)
|
|
506
|
-
* // => "-5"
|
|
507
353
|
*/
|
|
508
354
|
const signed = (value, digit = 0) => {
|
|
509
355
|
return new Intl.NumberFormat("en-US", {
|
|
@@ -515,9 +361,6 @@ const signed = (value, digit = 0) => {
|
|
|
515
361
|
* 手机号格式化脱敏 _ 隐藏中间 4 位数
|
|
516
362
|
* @param phone - 手机号码
|
|
517
363
|
* @returns 手机号格式化脱敏后的手机号
|
|
518
|
-
* @example
|
|
519
|
-
* maskPhone("13812345678")
|
|
520
|
-
* // => "138****5678"
|
|
521
364
|
*/
|
|
522
365
|
const maskPhone = (phone) => {
|
|
523
366
|
return phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
|
|
@@ -526,9 +369,6 @@ const maskPhone = (phone) => {
|
|
|
526
369
|
* 手机号格式化 _ 空格分隔
|
|
527
370
|
* @param phone - 手机号
|
|
528
371
|
* @returns 手机号空格格式化的手机号
|
|
529
|
-
* @example
|
|
530
|
-
* spacePhone("13812345678")
|
|
531
|
-
* // => "138 1234 5678"
|
|
532
372
|
*/
|
|
533
373
|
const spacePhone = (phone) => {
|
|
534
374
|
return phone.replace(/(\d{3})(\d{4})(\d{4})/, "$1 $2 $3");
|
|
@@ -537,9 +377,6 @@ const spacePhone = (phone) => {
|
|
|
537
377
|
* 每个单词首字母大写
|
|
538
378
|
* @param str - 字符串
|
|
539
379
|
* @returns 每个单词首字母大写后的字符串
|
|
540
|
-
* @example
|
|
541
|
-
* capitalize("hello world")
|
|
542
|
-
* // => "Hello World"
|
|
543
380
|
*/
|
|
544
381
|
const capitalize = (str) => {
|
|
545
382
|
return str.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
@@ -548,9 +385,6 @@ const capitalize = (str) => {
|
|
|
548
385
|
* 短横线连接转小驼峰(kebab-case → camelCase)
|
|
549
386
|
* @param str - 字符串
|
|
550
387
|
* @returns 转换后的小驼峰字符串
|
|
551
|
-
* @example
|
|
552
|
-
* kebabToCamel("hello-world")
|
|
553
|
-
* // => "helloWorld"
|
|
554
388
|
*/
|
|
555
389
|
const kebabToCamel = (str) => {
|
|
556
390
|
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
@@ -559,9 +393,6 @@ const kebabToCamel = (str) => {
|
|
|
559
393
|
* 大驼峰或小驼峰 _ 转为 ‘-’ 短横线连接
|
|
560
394
|
* @param str - 字符串
|
|
561
395
|
* @returns 大驼峰或小驼峰命名格式化的字符串
|
|
562
|
-
* @example
|
|
563
|
-
* camelToKebab("helloWorld")
|
|
564
|
-
* // => "hello-world"
|
|
565
396
|
*/
|
|
566
397
|
const camelToKebab = (str) => {
|
|
567
398
|
return str.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
@@ -572,9 +403,6 @@ const camelToKebab = (str) => {
|
|
|
572
403
|
* @param maxLength - 截断位置
|
|
573
404
|
* @param suffix - 自定义的替换截断后的内容
|
|
574
405
|
* @returns 超长文本截断后内容
|
|
575
|
-
* @example
|
|
576
|
-
* truncate("Hello World", 8)
|
|
577
|
-
* // => "Hello..."
|
|
578
406
|
*/
|
|
579
407
|
const truncate = (str, maxLength, suffix = "...") => {
|
|
580
408
|
if (str.length <= maxLength) return str;
|
|
@@ -586,9 +414,6 @@ const truncate = (str, maxLength, suffix = "...") => {
|
|
|
586
414
|
* @param maxWords - 截断位置
|
|
587
415
|
* @param suffix - 自定义的替换截断后的内容
|
|
588
416
|
* @returns 超长文本截断后内容
|
|
589
|
-
* @example
|
|
590
|
-
* truncateByWords("你好世界欢迎你", 4)
|
|
591
|
-
* // => "你好世界..."
|
|
592
417
|
*/
|
|
593
418
|
const truncateByWords = (str, maxWords, suffix = "...") => {
|
|
594
419
|
const chars = str.split("");
|
|
@@ -599,18 +424,12 @@ const truncateByWords = (str, maxWords, suffix = "...") => {
|
|
|
599
424
|
* 去除所有空格 _ 前后中间
|
|
600
425
|
* @param str - 内容
|
|
601
426
|
* @returns 去除空格后的内容
|
|
602
|
-
* @example
|
|
603
|
-
* trimAll(" hello world ")
|
|
604
|
-
* // => "helloworld"
|
|
605
427
|
*/
|
|
606
428
|
const trimAll = (str) => str.replace(/\s+/g, "");
|
|
607
429
|
/**
|
|
608
430
|
* 下划线转驼峰(snake_case → camelCase)
|
|
609
431
|
* @param str - 字符串
|
|
610
432
|
* @returns 转换后的驼峰字符串
|
|
611
|
-
* @example
|
|
612
|
-
* toCamel("hello_world")
|
|
613
|
-
* // => "helloWorld"
|
|
614
433
|
*/
|
|
615
434
|
const toCamel = (str) => {
|
|
616
435
|
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
@@ -619,9 +438,6 @@ const toCamel = (str) => {
|
|
|
619
438
|
* 首字母大写
|
|
620
439
|
* @param str - 字符串
|
|
621
440
|
* @returns 首字母大写后的字符串
|
|
622
|
-
* @example
|
|
623
|
-
* firstUpper("hello")
|
|
624
|
-
* // => "Hello"
|
|
625
441
|
*/
|
|
626
442
|
const firstUpper = (str) => {
|
|
627
443
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
@@ -630,9 +446,6 @@ const firstUpper = (str) => {
|
|
|
630
446
|
* 首字母小写
|
|
631
447
|
* @param str - 字符串
|
|
632
448
|
* @returns 首字母小写后的字符串
|
|
633
|
-
* @example
|
|
634
|
-
* firstLower("Hello")
|
|
635
|
-
* // => "hello"
|
|
636
449
|
*/
|
|
637
450
|
const firstLower = (str) => {
|
|
638
451
|
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
@@ -641,9 +454,6 @@ const firstLower = (str) => {
|
|
|
641
454
|
* 反转字符串
|
|
642
455
|
* @param str - 字符串
|
|
643
456
|
* @returns 反转后的字符串
|
|
644
|
-
* @example
|
|
645
|
-
* reverse("hello")
|
|
646
|
-
* // => "olleh"
|
|
647
457
|
*/
|
|
648
458
|
const reverse = (str) => {
|
|
649
459
|
return str.split("").reverse().join("");
|
|
@@ -654,9 +464,6 @@ const reverse = (str) => {
|
|
|
654
464
|
* 获取 localStorage
|
|
655
465
|
* @param key - 存储键名
|
|
656
466
|
* @returns 解析后的值,解析失败则返回原始字符串,键不存在返回 null
|
|
657
|
-
* @example
|
|
658
|
-
* localGet("user")
|
|
659
|
-
* // => { name: "张三" }
|
|
660
467
|
*/
|
|
661
468
|
const localGet = (key) => {
|
|
662
469
|
const value = localStorage.getItem(key);
|
|
@@ -671,8 +478,6 @@ const localGet = (key) => {
|
|
|
671
478
|
* 设置 localStorage
|
|
672
479
|
* @param key - 存储键名
|
|
673
480
|
* @param value - 存储值(会自动 JSON 序列化)
|
|
674
|
-
* @example
|
|
675
|
-
* localSet("user", { name: "张三" })
|
|
676
481
|
*/
|
|
677
482
|
const localSet = (key, value) => {
|
|
678
483
|
localStorage.setItem(key, JSON.stringify(value));
|
|
@@ -680,16 +485,12 @@ const localSet = (key, value) => {
|
|
|
680
485
|
/**
|
|
681
486
|
* 移除指定 localStorage
|
|
682
487
|
* @param key - 存储键名
|
|
683
|
-
* @example
|
|
684
|
-
* localRm("user")
|
|
685
488
|
*/
|
|
686
489
|
const localRm = (key) => {
|
|
687
490
|
localStorage.removeItem(key);
|
|
688
491
|
};
|
|
689
492
|
/**
|
|
690
493
|
* 清除所有 localStorage
|
|
691
|
-
* @example
|
|
692
|
-
* localClear()
|
|
693
494
|
*/
|
|
694
495
|
const localClear = () => {
|
|
695
496
|
localStorage.clear();
|
|
@@ -702,11 +503,6 @@ const localClear = () => {
|
|
|
702
503
|
* @param obj - 要拷贝的值
|
|
703
504
|
* @param hash - 内部 WeakMap 用于处理循环引用,调用方无需传入
|
|
704
505
|
* @returns 深拷贝后的值
|
|
705
|
-
* @example
|
|
706
|
-
* const obj = { a: 1, b: { c: 2 }, d: new Date() };
|
|
707
|
-
* const cloned = deepClone(obj);
|
|
708
|
-
* // cloned.b !== obj.b
|
|
709
|
-
* // cloned.d !== obj.d
|
|
710
506
|
*/
|
|
711
507
|
function deepClone(obj, hash = /* @__PURE__ */ new WeakMap()) {
|
|
712
508
|
if (obj === null || typeof obj !== "object") return obj;
|
|
@@ -750,9 +546,6 @@ function deepClone(obj, hash = /* @__PURE__ */ new WeakMap()) {
|
|
|
750
546
|
* (不支持函数、undefined、Date、RegExp、Map、Set 等)
|
|
751
547
|
* @param obj - 要拷贝的 JSON 安全值
|
|
752
548
|
* @returns 深拷贝后的值
|
|
753
|
-
* @example
|
|
754
|
-
* deepCloneWithJSON({ a: 1, b: [2, 3] })
|
|
755
|
-
* // => { a: 1, b: [2, 3] }
|
|
756
549
|
*/
|
|
757
550
|
function deepCloneWithJSON(obj) {
|
|
758
551
|
return JSON.parse(JSON.stringify(obj));
|
|
@@ -762,10 +555,6 @@ function deepCloneWithJSON(obj) {
|
|
|
762
555
|
* 仅拷贝第一层属性,嵌套对象仍共享引用
|
|
763
556
|
* @param obj - 要拷贝的对象或数组
|
|
764
557
|
* @returns 浅拷贝后的值
|
|
765
|
-
* @example
|
|
766
|
-
* const obj = { a: 1, b: { c: 2 } };
|
|
767
|
-
* const cloned = shallowClone(obj);
|
|
768
|
-
* // cloned.b === obj.b(共享引用)
|
|
769
558
|
*/
|
|
770
559
|
function shallowClone(obj) {
|
|
771
560
|
if (obj === null || typeof obj !== "object") return obj;
|
|
@@ -778,9 +567,6 @@ function shallowClone(obj) {
|
|
|
778
567
|
* Set 去重
|
|
779
568
|
* @param arr - 数组
|
|
780
569
|
* @returns 去重后的数组
|
|
781
|
-
* @example
|
|
782
|
-
* unique([1, 2, 2, 3])
|
|
783
|
-
* // => [1, 2, 3]
|
|
784
570
|
*/
|
|
785
571
|
const unique = (arr) => {
|
|
786
572
|
return [...new Set(arr)];
|
|
@@ -790,9 +576,6 @@ const unique = (arr) => {
|
|
|
790
576
|
* @param arr - 对象数组
|
|
791
577
|
* @param key - 用于去重判定的键名
|
|
792
578
|
* @returns 去重后的数组
|
|
793
|
-
* @example
|
|
794
|
-
* uniqueByKey([{ id: 1, name: "a" }, { id: 1, name: "b" }], "id")
|
|
795
|
-
* // => [{ id: 1, name: "a" }]
|
|
796
579
|
*/
|
|
797
580
|
const uniqueByKey = (arr, key) => {
|
|
798
581
|
return [...new Map(arr.map((item) => [item[key], item])).values()];
|
|
@@ -801,9 +584,6 @@ const uniqueByKey = (arr, key) => {
|
|
|
801
584
|
* 数值升序
|
|
802
585
|
* @param arr - 数值数组
|
|
803
586
|
* @returns 升序排序后的新数组
|
|
804
|
-
* @example
|
|
805
|
-
* sortNumAsc([3, 1, 2])
|
|
806
|
-
* // => [1, 2, 3]
|
|
807
587
|
*/
|
|
808
588
|
const sortNumAsc = (arr) => {
|
|
809
589
|
return [...arr].sort((a, b) => a - b);
|
|
@@ -812,9 +592,6 @@ const sortNumAsc = (arr) => {
|
|
|
812
592
|
* 数值降序
|
|
813
593
|
* @param arr - 数值数组
|
|
814
594
|
* @returns 降序排序后的新数组
|
|
815
|
-
* @example
|
|
816
|
-
* sortNumDesc([1, 3, 2])
|
|
817
|
-
* // => [3, 2, 1]
|
|
818
595
|
*/
|
|
819
596
|
const sortNumDesc = (arr) => {
|
|
820
597
|
return [...arr].sort((a, b) => b - a);
|
|
@@ -825,9 +602,6 @@ const sortNumDesc = (arr) => {
|
|
|
825
602
|
* @param key - 用于排序的属性名
|
|
826
603
|
* @param order - 排序方向,"asc" 升序 / "desc" 降序,默认 "asc"
|
|
827
604
|
* @returns 排序后的新数组
|
|
828
|
-
* @example
|
|
829
|
-
* sortByKey([{ age: 30 }, { age: 20 }], "age", "asc")
|
|
830
|
-
* // => [{ age: 20 }, { age: 30 }]
|
|
831
605
|
*/
|
|
832
606
|
const sortByKey = (arr, key, order = "asc") => {
|
|
833
607
|
return [...arr].sort((a, b) => order === "asc" ? a[key] - b[key] : b[key] - a[key]);
|
|
@@ -836,9 +610,6 @@ const sortByKey = (arr, key, order = "asc") => {
|
|
|
836
610
|
* 类数组转数组
|
|
837
611
|
* @param arrayLike - 类数组对象(如 NodeList、arguments)
|
|
838
612
|
* @returns 转换后的数组
|
|
839
|
-
* @example
|
|
840
|
-
* toArray(document.querySelectorAll("div"))
|
|
841
|
-
* // => [div, div, ...]
|
|
842
613
|
*/
|
|
843
614
|
const toArray = (arrayLike) => {
|
|
844
615
|
return Array.from(arrayLike);
|
|
@@ -847,9 +618,6 @@ const toArray = (arrayLike) => {
|
|
|
847
618
|
* 合并多个数组
|
|
848
619
|
* @param arrays - 一个或多个数组
|
|
849
620
|
* @returns 合并后的新数组
|
|
850
|
-
* @example
|
|
851
|
-
* mergeArrays([1, 2], [3, 4], [5])
|
|
852
|
-
* // => [1, 2, 3, 4, 5]
|
|
853
621
|
*/
|
|
854
622
|
const mergeArrays = (...arrays) => {
|
|
855
623
|
return [].concat(...arrays);
|
|
@@ -859,12 +627,6 @@ const mergeArrays = (...arrays) => {
|
|
|
859
627
|
* @param arr - 多维数组
|
|
860
628
|
* @param depth - 扁平化深度,默认 1(仅展开一层)。传 Infinity 可完全扁平化为一维
|
|
861
629
|
* @returns 扁平化后的数组
|
|
862
|
-
* @example
|
|
863
|
-
* flatten([1, [2, [3, 4]], 5])
|
|
864
|
-
* // => [1, 2, [3, 4], 5]
|
|
865
|
-
* @example
|
|
866
|
-
* flatten([1, [2, [3, 4]], 5], Infinity)
|
|
867
|
-
* // => [1, 2, 3, 4, 5]
|
|
868
630
|
*/
|
|
869
631
|
const flatten = (arr, depth = 1) => {
|
|
870
632
|
return arr.flat(depth);
|
|
@@ -875,9 +637,6 @@ const flatten = (arr, depth = 1) => {
|
|
|
875
637
|
* @param key - 要匹配的键名
|
|
876
638
|
* @param value - 要匹配的键值
|
|
877
639
|
* @returns 第一个匹配的对象,无匹配则返回 undefined
|
|
878
|
-
* @example
|
|
879
|
-
* arrFind([{ id: 1, name: "a" }, { id: 2, name: "b" }], "id", 2)
|
|
880
|
-
* // => { id: 2, name: "b" }
|
|
881
640
|
*/
|
|
882
641
|
const arrFind = (arr, key, value) => {
|
|
883
642
|
return arr.find((item) => item[key] === value);
|
|
@@ -887,9 +646,6 @@ const arrFind = (arr, key, value) => {
|
|
|
887
646
|
* @param arr - 对象数组
|
|
888
647
|
* @param key - 用于分组的属性名
|
|
889
648
|
* @returns 以属性值为键、对应数组为值的对象
|
|
890
|
-
* @example
|
|
891
|
-
* groupBy([{ type: "fruit", name: "apple" }, { type: "vegetable", name: "carrot" }], "type")
|
|
892
|
-
* // => { fruit: [{ type: "fruit", name: "apple" }], vegetable: [{ type: "vegetable", name: "carrot" }] }
|
|
893
649
|
*/
|
|
894
650
|
const groupBy = (arr, key) => {
|
|
895
651
|
return arr.reduce((acc, item) => {
|
|
@@ -903,9 +659,6 @@ const groupBy = (arr, key) => {
|
|
|
903
659
|
* 移除对象中值为空(null / undefined / 空字符串)的属性
|
|
904
660
|
* @param obj - 待过滤的对象
|
|
905
661
|
* @returns 过滤后的新对象
|
|
906
|
-
* @example
|
|
907
|
-
* filterEmptyValues({ a: 1, b: "", c: null, d: 3 })
|
|
908
|
-
* // => { a: 1, d: 3 }
|
|
909
662
|
*/
|
|
910
663
|
const filterEmptyValues = (obj) => {
|
|
911
664
|
return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== null && v !== void 0 && v !== ""));
|
|
@@ -915,9 +668,6 @@ const filterEmptyValues = (obj) => {
|
|
|
915
668
|
* @param length - 数组长度
|
|
916
669
|
* @param mapFn - 映射函数,接收索引返回元素值,默认为返回索引
|
|
917
670
|
* @returns 生成的数组
|
|
918
|
-
* @example
|
|
919
|
-
* createRange(5)
|
|
920
|
-
* // => [0, 1, 2, 3, 4]
|
|
921
671
|
*/
|
|
922
672
|
const createRange = (length, mapFn) => {
|
|
923
673
|
return Array.from({ length }, (_, i) => mapFn ? mapFn(i) : i);
|
|
@@ -929,8 +679,6 @@ const createRange = (length, mapFn) => {
|
|
|
929
679
|
* @param name - Cookie 名称
|
|
930
680
|
* @param value - Cookie 值
|
|
931
681
|
* @param days - 有效天数,默认 7 天
|
|
932
|
-
* @example
|
|
933
|
-
* setCookie("token", "abc123", 30)
|
|
934
682
|
*/
|
|
935
683
|
const setCookie = (name, value, days = 0) => {
|
|
936
684
|
const expires = /* @__PURE__ */ new Date();
|
|
@@ -941,9 +689,6 @@ const setCookie = (name, value, days = 0) => {
|
|
|
941
689
|
* 获取 Cookie
|
|
942
690
|
* @param name - Cookie 名称
|
|
943
691
|
* @returns Cookie 值,不存在则返回 null
|
|
944
|
-
* @example
|
|
945
|
-
* getCookie("token")
|
|
946
|
-
* // => "abc123"
|
|
947
692
|
*/
|
|
948
693
|
const getCookie = (name) => {
|
|
949
694
|
const match = document.cookie.match(new RegExp("(^| )" + encodeURIComponent(name) + "=([^;]+)"));
|
|
@@ -952,8 +697,6 @@ const getCookie = (name) => {
|
|
|
952
697
|
/**
|
|
953
698
|
* 删除 Cookie
|
|
954
699
|
* @param name - Cookie 名称
|
|
955
|
-
* @example
|
|
956
|
-
* delCookie("token")
|
|
957
700
|
*/
|
|
958
701
|
const delCookie = (name) => {
|
|
959
702
|
setCookie(name, "", -1);
|
|
@@ -964,9 +707,6 @@ const delCookie = (name) => {
|
|
|
964
707
|
* 获取 URL 参数对象
|
|
965
708
|
* @param url - URL 字符串,默认使用当前页面地址
|
|
966
709
|
* @returns 参数键值对对象
|
|
967
|
-
* @example
|
|
968
|
-
* getUrlParams("https://example.com?a=1&b=2")
|
|
969
|
-
* // => { a: "1", b: "2" }
|
|
970
710
|
*/
|
|
971
711
|
const getUrlParams = (url) => {
|
|
972
712
|
const params = {};
|
|
@@ -980,9 +720,6 @@ const getUrlParams = (url) => {
|
|
|
980
720
|
* @param key - 参数名
|
|
981
721
|
* @param url - URL 字符串,默认使用当前页面地址
|
|
982
722
|
* @returns 参数值,不存在则返回 null
|
|
983
|
-
* @example
|
|
984
|
-
* getUrlParam("a", "https://example.com?a=1")
|
|
985
|
-
* // => "1"
|
|
986
723
|
*/
|
|
987
724
|
const getUrlParam = (key, url) => {
|
|
988
725
|
return new URL(url || window.location.href).searchParams.get(key);
|
|
@@ -991,9 +728,6 @@ const getUrlParam = (key, url) => {
|
|
|
991
728
|
* 对象转 URL 参数字符串
|
|
992
729
|
* @param params - 参数键值对对象,值为 null/undefined 的项会被过滤
|
|
993
730
|
* @returns URL 参数字符串(不含 ? 前缀)
|
|
994
|
-
* @example
|
|
995
|
-
* toQueryString({ a: 1, b: "hello", c: null })
|
|
996
|
-
* // => "a=1&b=hello"
|
|
997
731
|
*/
|
|
998
732
|
const toQueryString = (params) => {
|
|
999
733
|
return Object.entries(params).filter(([, v]) => v !== void 0 && v !== null).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&");
|
|
@@ -1003,9 +737,6 @@ const toQueryString = (params) => {
|
|
|
1003
737
|
* 优先使用 Clipboard API,失败时降级为 execCommand
|
|
1004
738
|
* @param text - 要复制的文本
|
|
1005
739
|
* @returns 复制成功返回 true,失败返回 false
|
|
1006
|
-
* @example
|
|
1007
|
-
* await copyToClipboard("Hello World")
|
|
1008
|
-
* // => true
|
|
1009
740
|
*/
|
|
1010
741
|
const copyToClipboard = async (text) => {
|
|
1011
742
|
if (navigator.clipboard) try {
|
|
@@ -1029,8 +760,6 @@ const copyToClipboard = async (text) => {
|
|
|
1029
760
|
* @param content - 文件内容
|
|
1030
761
|
* @param filename - 文件名
|
|
1031
762
|
* @param mimeType - MIME 类型,默认 "text/plain"
|
|
1032
|
-
* @example
|
|
1033
|
-
* downloadFile("Hello", "hello.txt")
|
|
1034
763
|
*/
|
|
1035
764
|
const downloadFile = (content, filename, mimeType = "text/plain") => {
|
|
1036
765
|
const blob = new Blob([content], { type: mimeType });
|
|
@@ -1045,8 +774,6 @@ const downloadFile = (content, filename, mimeType = "text/plain") => {
|
|
|
1045
774
|
* 导出 JSON 为文件
|
|
1046
775
|
* @param data - 要导出的数据
|
|
1047
776
|
* @param filename - 文件名,默认 "data.json"
|
|
1048
|
-
* @example
|
|
1049
|
-
* exportJSON({ name: "张三", age: 30 })
|
|
1050
777
|
*/
|
|
1051
778
|
const exportJSON = (data, filename = "data.json") => {
|
|
1052
779
|
downloadFile(JSON.stringify(data, null, 2), filename, "application/json");
|
|
@@ -1054,8 +781,6 @@ const exportJSON = (data, filename = "data.json") => {
|
|
|
1054
781
|
/**
|
|
1055
782
|
* 滚动到顶部
|
|
1056
783
|
* @param behavior - 滚动行为,"smooth" 平滑 / "auto" 瞬间,默认 "smooth"
|
|
1057
|
-
* @example
|
|
1058
|
-
* scrollToTop()
|
|
1059
784
|
*/
|
|
1060
785
|
const scrollToTop = (behavior = "smooth") => {
|
|
1061
786
|
window.scrollTo({
|
|
@@ -1066,8 +791,6 @@ const scrollToTop = (behavior = "smooth") => {
|
|
|
1066
791
|
/**
|
|
1067
792
|
* 滚动到底部
|
|
1068
793
|
* @param behavior - 滚动行为,"smooth" 平滑 / "auto" 瞬间,默认 "smooth"
|
|
1069
|
-
* @example
|
|
1070
|
-
* scrollToBottom()
|
|
1071
794
|
*/
|
|
1072
795
|
const scrollToBottom = (behavior = "smooth") => {
|
|
1073
796
|
window.scrollTo({
|
|
@@ -1079,9 +802,6 @@ const scrollToBottom = (behavior = "smooth") => {
|
|
|
1079
802
|
* 监听页面滚动(requestAnimationFrame 节流)
|
|
1080
803
|
* @param callback - 滚动回调,接收当前 scrollY 值
|
|
1081
804
|
* @returns 清理函数,调用后移除事件监听
|
|
1082
|
-
* @example
|
|
1083
|
-
* const cleanup = onScroll((y) => console.log(y));
|
|
1084
|
-
* cleanup(); // 停止监听
|
|
1085
805
|
*/
|
|
1086
806
|
const onScroll = (callback) => {
|
|
1087
807
|
let ticking = false;
|
|
@@ -1104,12 +824,6 @@ const onScroll = (callback) => {
|
|
|
1104
824
|
* @param onLeave - 元素离开可视区域时的回调(可选)
|
|
1105
825
|
* @param options - IntersectionObserver 配置项
|
|
1106
826
|
* @returns 清理函数,调用后停止观察
|
|
1107
|
-
* @example
|
|
1108
|
-
* const cleanup = observeIntersection(
|
|
1109
|
-
* document.querySelector(".footer")!,
|
|
1110
|
-
* () => loadMore(10),
|
|
1111
|
-
* );
|
|
1112
|
-
* cleanup(); // 停止观察
|
|
1113
827
|
*/
|
|
1114
828
|
const observeIntersection = (target, onEnter, onLeave, options) => {
|
|
1115
829
|
const observer = new IntersectionObserver((entries) => {
|
|
@@ -1130,10 +844,6 @@ const observeIntersection = (target, onEnter, onLeave, options) => {
|
|
|
1130
844
|
* @param options.leading - 首次调用是否立即执行,默认 false
|
|
1131
845
|
* @param options.trailing - 停止调用后是否延迟执行,默认 true
|
|
1132
846
|
* @returns 防抖后的函数,附带 cancel 方法
|
|
1133
|
-
* @example
|
|
1134
|
-
* const fn = debounce((val: string) => console.log(val), 500)
|
|
1135
|
-
* fn("a"); fn("b"); fn("c")
|
|
1136
|
-
* // => "c"
|
|
1137
847
|
*/
|
|
1138
848
|
const debounce = (fn, delay = 300, { leading = false, trailing = true } = {}) => {
|
|
1139
849
|
let timer = null;
|
|
@@ -1170,10 +880,6 @@ const debounce = (fn, delay = 300, { leading = false, trailing = true } = {}) =>
|
|
|
1170
880
|
* @param options.leading - 首次调用是否立即执行,默认 true
|
|
1171
881
|
* @param options.trailing - 最后一次调用后是否尾部执行,默认 true
|
|
1172
882
|
* @returns 节流后的函数,附带 cancel 方法
|
|
1173
|
-
* @example
|
|
1174
|
-
* const fn = throttle((val: string) => console.log(val), 500)
|
|
1175
|
-
* fn("a"); fn("b"); fn("c")
|
|
1176
|
-
* // => "a",500ms 后输出 "c"
|
|
1177
883
|
*/
|
|
1178
884
|
const throttle = (fn, interval = 300, { leading = true, trailing = true } = {}) => {
|
|
1179
885
|
let timer = null;
|