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