nhanh-pure-function 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Index.d.ts +5 -1
- package/lib/Index.js +2 -1
- package/lib/User.d.ts +85 -10
- package/lib/User.js +306 -37
- package/lib/Utility.d.ts +60 -8
- package/lib/Utility.js +95 -16
- package/lib/index.css +8 -0
- package/lib/index.less +5 -0
- package/lib/test.ts +1 -0
- package/package.json +1 -1
package/lib/Index.d.ts
CHANGED
package/lib/Index.js
CHANGED
package/lib/User.d.ts
CHANGED
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
* @param {滚动标签} element
|
|
4
4
|
* @param {触底事件} callback
|
|
5
5
|
*/
|
|
6
|
-
export function _AddScrollBottomListener(
|
|
6
|
+
export function _AddScrollBottomListener(
|
|
7
|
+
element: HTMLElement,
|
|
8
|
+
callback: Function
|
|
9
|
+
): void;
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* 自动处理 currentPage * pageSize > total
|
|
10
13
|
* @param ask 请求方法
|
|
11
14
|
* @param config 请求参数
|
|
12
15
|
*/
|
|
13
|
-
export function _PagingQuery<Ask extends
|
|
16
|
+
export function _PagingQuery<Ask extends (...args: any[]) => any>(
|
|
14
17
|
ask: Ask,
|
|
15
18
|
config: {
|
|
16
19
|
currentPage: number;
|
|
@@ -67,10 +70,10 @@ export function _SetQuantifierAttribute<T>(
|
|
|
67
70
|
*/
|
|
68
71
|
export function _SetDefaultValue<T>(
|
|
69
72
|
data: T,
|
|
70
|
-
options
|
|
73
|
+
options?: {
|
|
71
74
|
defaultValue?: string;
|
|
72
75
|
fieldsNotRequiringAction?: (string | number | symbol)[];
|
|
73
|
-
}
|
|
76
|
+
}
|
|
74
77
|
): T;
|
|
75
78
|
|
|
76
79
|
/**
|
|
@@ -113,7 +116,7 @@ export function _SetPhoto<T>(
|
|
|
113
116
|
*/
|
|
114
117
|
export function _Exhibit_details<T>(
|
|
115
118
|
data: T,
|
|
116
|
-
options
|
|
119
|
+
options?: {
|
|
117
120
|
dictionaryOptions?: { [key in keyof T]: { [key: string | number]: any } };
|
|
118
121
|
dictionaryLabel?: (keyof T)[];
|
|
119
122
|
dictionaryLabelJoin?: (keyof T)[];
|
|
@@ -138,7 +141,7 @@ export function _Exhibit_details<T>(
|
|
|
138
141
|
filterLabel?: (keyof T)[];
|
|
139
142
|
|
|
140
143
|
defaultValue?: string;
|
|
141
|
-
}
|
|
144
|
+
}
|
|
142
145
|
): T;
|
|
143
146
|
|
|
144
147
|
// 定义加载状态更新函数类型
|
|
@@ -146,7 +149,7 @@ type LoadingStateUpdater = (newState: boolean) => void;
|
|
|
146
149
|
// 定义加载控制器的类型
|
|
147
150
|
interface LoadingController {
|
|
148
151
|
invokers: Set<any>; // 假设invoker可以是任何类型
|
|
149
|
-
timer:
|
|
152
|
+
timer: number | null;
|
|
150
153
|
startTime: number;
|
|
151
154
|
loadingState: LoadingStateUpdater;
|
|
152
155
|
delayTime: number;
|
|
@@ -156,11 +159,9 @@ interface LoadingController {
|
|
|
156
159
|
export class _LoadingController {
|
|
157
160
|
#controllersCollection: Map<string, LoadingController>;
|
|
158
161
|
|
|
159
|
-
constructor() {}
|
|
160
|
-
|
|
161
162
|
// addController方法的类型定义
|
|
162
163
|
addController(
|
|
163
|
-
key
|
|
164
|
+
key: string,
|
|
164
165
|
config: {
|
|
165
166
|
loadingState: LoadingStateUpdater;
|
|
166
167
|
delayTime?: number;
|
|
@@ -183,3 +184,77 @@ export class _LoadingController {
|
|
|
183
184
|
// stopLoading方法的类型定义
|
|
184
185
|
stopLoading(invoker: any, key?: string): void;
|
|
185
186
|
}
|
|
187
|
+
|
|
188
|
+
type UiLibrary = "naiveUI" | "ElementPlus" | "Element";
|
|
189
|
+
/**
|
|
190
|
+
* 点击非指定dom(包含子级dom)时执行 callback
|
|
191
|
+
* @param querySelector 允许点击的 dom 顶层祖先元素选择器
|
|
192
|
+
* @param callback 满足条件时执行的回调
|
|
193
|
+
*
|
|
194
|
+
* @param options 其他配置
|
|
195
|
+
* @param options.uiLibrary 项目使用的 ui库 , 用于排除 ui库 创建的元素 , 避免点击 ui库 创建的元素时意外的执行 callback
|
|
196
|
+
* @param options.isClickAllowed 是否允许该点击 ( 如果不确定可以返回 undefined )
|
|
197
|
+
*/
|
|
198
|
+
export function _CloseOnOutsideClick(
|
|
199
|
+
querySelector: string[],
|
|
200
|
+
callback: Function,
|
|
201
|
+
options?: {
|
|
202
|
+
uiLibrary?: UiLibrary[];
|
|
203
|
+
isClickAllowed?: (event: MouseEvent) => boolean | undefined;
|
|
204
|
+
}
|
|
205
|
+
): void;
|
|
206
|
+
|
|
207
|
+
/** 拖拽配置 */
|
|
208
|
+
type DragOption = {
|
|
209
|
+
/** 拖拽范围限制 */
|
|
210
|
+
limit?: {
|
|
211
|
+
max: {
|
|
212
|
+
top: number;
|
|
213
|
+
left: number;
|
|
214
|
+
};
|
|
215
|
+
min: {
|
|
216
|
+
top: number;
|
|
217
|
+
left: number;
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
/** 指定的拖拽元素 */
|
|
221
|
+
dragDom?: HTMLElement;
|
|
222
|
+
};
|
|
223
|
+
/** 拖拽 */
|
|
224
|
+
export class Drag {
|
|
225
|
+
/**
|
|
226
|
+
* 初始化拖拽
|
|
227
|
+
* @param dom 被拖拽的元素
|
|
228
|
+
* @param option 拖拽配置
|
|
229
|
+
*/
|
|
230
|
+
init(dom: HTMLElement, option?: DragOption): void;
|
|
231
|
+
/** 结束拖拽 */
|
|
232
|
+
finish(): void;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** 更新后的位置信息 */
|
|
236
|
+
type UpdateValue = {
|
|
237
|
+
top: number;
|
|
238
|
+
left: number;
|
|
239
|
+
percentage?: {
|
|
240
|
+
top: number;
|
|
241
|
+
left: number;
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
/** 局部拖拽配置 */
|
|
245
|
+
type LocalDragOptions = {
|
|
246
|
+
limit?: DragOption["limit"];
|
|
247
|
+
update_move?: (value: UpdateValue) => void | undefined;
|
|
248
|
+
update_up?: (value: UpdateValue) => void | undefined;
|
|
249
|
+
};
|
|
250
|
+
/** 局部拖拽 计算位置距离/百分比 */
|
|
251
|
+
export class LocalDrag {
|
|
252
|
+
/**
|
|
253
|
+
* 初始化拖拽
|
|
254
|
+
* @param parentDom 被拖拽元素的祖先元素
|
|
255
|
+
* @param option 局部拖拽配置
|
|
256
|
+
*/
|
|
257
|
+
init(parentDom: HTMLElement, options?: LocalDragOptions): void;
|
|
258
|
+
/** 结束拖拽 */
|
|
259
|
+
finish(): void;
|
|
260
|
+
}
|
package/lib/User.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _IsObject, _IsWithinErrorMargin, _NotNull } from
|
|
1
|
+
import { _IsObject, _IsWithinErrorMargin, _NotNull } from "./Utility";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* 添加滚动触底事件
|
|
@@ -6,8 +6,14 @@ import { _IsObject, _IsWithinErrorMargin, _NotNull } from './Utility';
|
|
|
6
6
|
* @param {触底事件} callback
|
|
7
7
|
*/
|
|
8
8
|
export function _AddScrollBottomListener(element, callback) {
|
|
9
|
-
element.addEventListener(
|
|
10
|
-
if (
|
|
9
|
+
element.addEventListener("scroll", function () {
|
|
10
|
+
if (
|
|
11
|
+
_IsWithinErrorMargin(
|
|
12
|
+
element.scrollTop + element.clientHeight,
|
|
13
|
+
element.scrollHeight,
|
|
14
|
+
2
|
|
15
|
+
)
|
|
16
|
+
) {
|
|
11
17
|
callback();
|
|
12
18
|
}
|
|
13
19
|
});
|
|
@@ -53,25 +59,25 @@ export function _FormatNumberWithUnit(number, config = {}) {
|
|
|
53
59
|
const { join, suffix, integer } = Object.assign(
|
|
54
60
|
{
|
|
55
61
|
join: true,
|
|
56
|
-
suffix:
|
|
57
|
-
integer: false
|
|
62
|
+
suffix: "",
|
|
63
|
+
integer: false,
|
|
58
64
|
},
|
|
59
65
|
config
|
|
60
66
|
);
|
|
61
67
|
|
|
62
68
|
function _join(value, suffix, plus = true) {
|
|
63
|
-
value = (plus ?
|
|
69
|
+
value = (plus ? "" : "-") + value;
|
|
64
70
|
if (join) return value + suffix;
|
|
65
71
|
else return [value, suffix];
|
|
66
72
|
}
|
|
67
73
|
|
|
68
|
-
if (typeof number ==
|
|
74
|
+
if (typeof number == "string") {
|
|
69
75
|
if (!/^\d+$/.test(number.trim())) {
|
|
70
|
-
console.error(
|
|
76
|
+
console.error("错误输入:", number);
|
|
71
77
|
return _join(0, suffix);
|
|
72
78
|
}
|
|
73
|
-
} else if (typeof number !=
|
|
74
|
-
console.error(
|
|
79
|
+
} else if (typeof number != "number") {
|
|
80
|
+
console.error("错误输入:", number);
|
|
75
81
|
return _join(0, suffix);
|
|
76
82
|
}
|
|
77
83
|
|
|
@@ -83,7 +89,21 @@ export function _FormatNumberWithUnit(number, config = {}) {
|
|
|
83
89
|
const plus = number >= 0;
|
|
84
90
|
number = Math.abs(number);
|
|
85
91
|
|
|
86
|
-
const units = [
|
|
92
|
+
const units = [
|
|
93
|
+
"",
|
|
94
|
+
"万",
|
|
95
|
+
"亿",
|
|
96
|
+
"兆",
|
|
97
|
+
"京",
|
|
98
|
+
"垓",
|
|
99
|
+
"秭",
|
|
100
|
+
"穰",
|
|
101
|
+
"沟",
|
|
102
|
+
"涧",
|
|
103
|
+
"正",
|
|
104
|
+
"载",
|
|
105
|
+
"极",
|
|
106
|
+
];
|
|
87
107
|
const digits = Math.floor(Math.log10(number) / 4); // 计算位数
|
|
88
108
|
|
|
89
109
|
// 不超过万位的数字直接返回
|
|
@@ -109,16 +129,17 @@ export function _FormatNumberWithUnit(number, config = {}) {
|
|
|
109
129
|
*/
|
|
110
130
|
export function _SetQuantifierAttribute(data, options = []) {
|
|
111
131
|
if (!_IsObject(data)) {
|
|
112
|
-
console.error(
|
|
132
|
+
console.error("异常输入:", data);
|
|
113
133
|
return data;
|
|
114
134
|
}
|
|
115
135
|
|
|
116
136
|
options.forEach((item) => {
|
|
117
|
-
if (typeof item ===
|
|
137
|
+
if (typeof item === "string") {
|
|
118
138
|
data[item] = _FormatNumberWithUnit(data[item]);
|
|
119
139
|
} else if (Array.isArray(item)) {
|
|
120
140
|
const [label, config] = data[item];
|
|
121
|
-
if (_NotNull(label) && _IsObject(config))
|
|
141
|
+
if (_NotNull(label) && _IsObject(config))
|
|
142
|
+
data[label] = _FormatNumberWithUnit(label, config);
|
|
122
143
|
}
|
|
123
144
|
});
|
|
124
145
|
return data;
|
|
@@ -132,11 +153,11 @@ export function _SetQuantifierAttribute(data, options = []) {
|
|
|
132
153
|
*/
|
|
133
154
|
export function _SetDefaultValue(data, options = {}) {
|
|
134
155
|
if (!_IsObject(data)) {
|
|
135
|
-
console.error(
|
|
156
|
+
console.error("异常输入:", data);
|
|
136
157
|
return data;
|
|
137
158
|
}
|
|
138
159
|
|
|
139
|
-
const { defaultValue =
|
|
160
|
+
const { defaultValue = "--", fieldsNotRequiringAction } = options;
|
|
140
161
|
|
|
141
162
|
for (const key in data) {
|
|
142
163
|
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
@@ -162,7 +183,7 @@ export function _SetDefaultValue(data, options = {}) {
|
|
|
162
183
|
*/
|
|
163
184
|
export function _SetDictionary(data, options = {}) {
|
|
164
185
|
if (!_IsObject(data)) {
|
|
165
|
-
console.error(
|
|
186
|
+
console.error("异常输入:", data);
|
|
166
187
|
return data;
|
|
167
188
|
}
|
|
168
189
|
|
|
@@ -170,7 +191,7 @@ export function _SetDictionary(data, options = {}) {
|
|
|
170
191
|
dictionaryLabel = [],
|
|
171
192
|
dictionaryLabelJoin = [],
|
|
172
193
|
dictionaryOptions,
|
|
173
|
-
defaultValue =
|
|
194
|
+
defaultValue = "--",
|
|
174
195
|
} = options;
|
|
175
196
|
|
|
176
197
|
if (dictionaryOptions) {
|
|
@@ -188,11 +209,11 @@ export function _SetDictionary(data, options = {}) {
|
|
|
188
209
|
}
|
|
189
210
|
});
|
|
190
211
|
dictionaryLabelJoin.forEach((label) => {
|
|
191
|
-
if (_NotNull(data[label]) && data[label] !=
|
|
212
|
+
if (_NotNull(data[label]) && data[label] != "") {
|
|
192
213
|
const options = dictionaryOptions[label];
|
|
193
214
|
if (options) {
|
|
194
|
-
const oldvalue = data[label].split(
|
|
195
|
-
data[label] =
|
|
215
|
+
const oldvalue = data[label].split(",");
|
|
216
|
+
data[label] = "";
|
|
196
217
|
oldvalue.forEach((_label) => {
|
|
197
218
|
data[label] += options[_label];
|
|
198
219
|
});
|
|
@@ -216,7 +237,7 @@ export function _SetDictionary(data, options = {}) {
|
|
|
216
237
|
*/
|
|
217
238
|
export function _SetPhoto(data, options = {}) {
|
|
218
239
|
if (!_IsObject(data)) {
|
|
219
|
-
console.error(
|
|
240
|
+
console.error("异常输入:", data);
|
|
220
241
|
return data;
|
|
221
242
|
}
|
|
222
243
|
|
|
@@ -226,8 +247,8 @@ export function _SetPhoto(data, options = {}) {
|
|
|
226
247
|
label.forEach((label) => {
|
|
227
248
|
const defaultValue = (defaultUrl && defaultUrl[label]) || [];
|
|
228
249
|
const value = data[label];
|
|
229
|
-
if (typeof value ===
|
|
230
|
-
data[label] = value.split(
|
|
250
|
+
if (typeof value === "string") {
|
|
251
|
+
data[label] = value.split(",").filter(Boolean);
|
|
231
252
|
} else {
|
|
232
253
|
data[label] = defaultValue;
|
|
233
254
|
}
|
|
@@ -245,7 +266,7 @@ export function _SetPhoto(data, options = {}) {
|
|
|
245
266
|
*/
|
|
246
267
|
export function _Exhibit_details(data, options = {}) {
|
|
247
268
|
if (!_IsObject(data)) {
|
|
248
|
-
console.error(
|
|
269
|
+
console.error("异常输入:", data);
|
|
249
270
|
return {};
|
|
250
271
|
}
|
|
251
272
|
|
|
@@ -263,19 +284,19 @@ export function _Exhibit_details(data, options = {}) {
|
|
|
263
284
|
|
|
264
285
|
filterLabel = [],
|
|
265
286
|
|
|
266
|
-
defaultValue =
|
|
287
|
+
defaultValue = "--",
|
|
267
288
|
} = options;
|
|
268
289
|
|
|
269
290
|
_SetDictionary(data, {
|
|
270
291
|
dictionaryLabel,
|
|
271
292
|
dictionaryLabelJoin,
|
|
272
293
|
dictionaryOptions,
|
|
273
|
-
defaultValue
|
|
294
|
+
defaultValue,
|
|
274
295
|
});
|
|
275
296
|
|
|
276
297
|
_SetPhoto(data, {
|
|
277
298
|
label: photoLabel,
|
|
278
|
-
defaultUrl: photoDefaultUrl
|
|
299
|
+
defaultUrl: photoDefaultUrl,
|
|
279
300
|
});
|
|
280
301
|
|
|
281
302
|
_SetQuantifierAttribute(data, quantifierLabel);
|
|
@@ -288,12 +309,12 @@ export function _Exhibit_details(data, options = {}) {
|
|
|
288
309
|
.concat(
|
|
289
310
|
quantifierLabel
|
|
290
311
|
.map((item) => {
|
|
291
|
-
if (typeof item ==
|
|
312
|
+
if (typeof item == "string") return item;
|
|
292
313
|
if (Array.isArray(item)) return item[0];
|
|
293
314
|
})
|
|
294
315
|
.filter(Boolean)
|
|
295
316
|
)
|
|
296
|
-
.concat(filterLabel)
|
|
317
|
+
.concat(filterLabel),
|
|
297
318
|
});
|
|
298
319
|
|
|
299
320
|
return data;
|
|
@@ -304,14 +325,14 @@ export class _LoadingController {
|
|
|
304
325
|
#controllersCollection = new Map();
|
|
305
326
|
constructor() {}
|
|
306
327
|
|
|
307
|
-
addController(key =
|
|
328
|
+
addController(key = "default", config) {
|
|
308
329
|
if (this.#controllersCollection.has(key))
|
|
309
|
-
throw new Error(
|
|
330
|
+
throw new Error("key为: " + key + " 的loading控制器已存在, 请重命名。");
|
|
310
331
|
|
|
311
332
|
const {
|
|
312
333
|
loadingState /** 更新/获取 loading 状态的方法 */,
|
|
313
334
|
delayTime = 200 /** 延迟时间 */,
|
|
314
|
-
minDisplayTime = 400 /** 最少显示时间
|
|
335
|
+
minDisplayTime = 400 /** 最少显示时间 */,
|
|
315
336
|
} = config;
|
|
316
337
|
this.#controllersCollection.set(key, {
|
|
317
338
|
invokers: new Set(),
|
|
@@ -319,7 +340,7 @@ export class _LoadingController {
|
|
|
319
340
|
startTime: 0,
|
|
320
341
|
loadingState,
|
|
321
342
|
delayTime,
|
|
322
|
-
minDisplayTime
|
|
343
|
+
minDisplayTime,
|
|
323
344
|
});
|
|
324
345
|
}
|
|
325
346
|
|
|
@@ -327,9 +348,10 @@ export class _LoadingController {
|
|
|
327
348
|
this.#controllersCollection.delete(key);
|
|
328
349
|
}
|
|
329
350
|
|
|
330
|
-
getController(key =
|
|
351
|
+
getController(key = "default") {
|
|
331
352
|
const controller = this.#controllersCollection.get(key);
|
|
332
|
-
if (!controller)
|
|
353
|
+
if (!controller)
|
|
354
|
+
throw new Error("还未添加key为: " + key + " 的loading控制器");
|
|
333
355
|
return controller;
|
|
334
356
|
}
|
|
335
357
|
|
|
@@ -378,10 +400,257 @@ export class _LoadingController {
|
|
|
378
400
|
if (displayTime >= minDisplayTime) {
|
|
379
401
|
this.resetController(key);
|
|
380
402
|
} else {
|
|
381
|
-
setTimeout(
|
|
403
|
+
setTimeout(
|
|
404
|
+
() => this.stopLoading(invoker, key),
|
|
405
|
+
displayTime - minDisplayTime
|
|
406
|
+
);
|
|
382
407
|
}
|
|
383
408
|
} else {
|
|
384
409
|
invokers.delete(invoker);
|
|
385
410
|
}
|
|
386
411
|
}
|
|
387
412
|
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* 点击非指定dom(包含子级dom)时执行 callback
|
|
416
|
+
* @param querySelector 允许点击的 dom 顶层祖先元素选择器
|
|
417
|
+
* @param callback 满足条件时执行的回调
|
|
418
|
+
*
|
|
419
|
+
* @param options 其他配置
|
|
420
|
+
* @param options.uiLibrary 项目使用的 ui库 , 用于排除 ui库 创建的元素 , 避免点击 ui库 创建的元素时意外的执行 callback
|
|
421
|
+
* @param options.isClickAllowed 是否允许该点击 ( 如果不确定可以返回 undefined )
|
|
422
|
+
*/
|
|
423
|
+
export function _CloseOnOutsideClick(
|
|
424
|
+
querySelector,
|
|
425
|
+
callback,
|
|
426
|
+
options = {
|
|
427
|
+
uiLibrary: ["naiveUI", "ElementPlus", "Element"],
|
|
428
|
+
}
|
|
429
|
+
) {
|
|
430
|
+
function end() {
|
|
431
|
+
callback();
|
|
432
|
+
document.removeEventListener("mousedown", mousedown);
|
|
433
|
+
}
|
|
434
|
+
function mousedown(event) {
|
|
435
|
+
const { isClickAllowed, uiLibrary } = options;
|
|
436
|
+
|
|
437
|
+
if (isClickAllowed) {
|
|
438
|
+
const bool = isClickAllowed(event);
|
|
439
|
+
if (bool) return;
|
|
440
|
+
if (bool === false) return end();
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const target = event.target;
|
|
444
|
+
|
|
445
|
+
/** 元素这时可能已经被删除了 */
|
|
446
|
+
if (!target?.closest("body")) return;
|
|
447
|
+
|
|
448
|
+
const UI = (function (obj) {
|
|
449
|
+
const arr = [];
|
|
450
|
+
for (const key in obj) {
|
|
451
|
+
if (Object.hasOwnProperty.call(obj, key)) {
|
|
452
|
+
if (uiLibrary.includes(key)) arr.concat(obj[key]);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return arr;
|
|
456
|
+
})({
|
|
457
|
+
naiveUI: [
|
|
458
|
+
".v-binder-follower-container",
|
|
459
|
+
".n-image-preview-container",
|
|
460
|
+
".n-modal-container",
|
|
461
|
+
],
|
|
462
|
+
ElementPlus: ["el-popper"],
|
|
463
|
+
Element: ["el-popper"],
|
|
464
|
+
});
|
|
465
|
+
const isClickable = querySelector
|
|
466
|
+
.concat(UI)
|
|
467
|
+
.some((className) => Boolean(target?.closest(className)));
|
|
468
|
+
|
|
469
|
+
if (!isClickable) end();
|
|
470
|
+
}
|
|
471
|
+
requestAnimationFrame(() =>
|
|
472
|
+
document.addEventListener("mousedown", mousedown)
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/** 拖拽dom */
|
|
477
|
+
export class Drag {
|
|
478
|
+
#dom = null;
|
|
479
|
+
#isAllowed = false;
|
|
480
|
+
#eventFunction = {};
|
|
481
|
+
#pageX = 0;
|
|
482
|
+
#pageY = 0;
|
|
483
|
+
#top = 0;
|
|
484
|
+
#left = 0;
|
|
485
|
+
#limit;
|
|
486
|
+
#dragDom;
|
|
487
|
+
|
|
488
|
+
init(dom, option) {
|
|
489
|
+
this.#dom = dom;
|
|
490
|
+
this.#limit = option?.limit;
|
|
491
|
+
this.#dragDom = option?.dragDom;
|
|
492
|
+
this.#eventFunction = {
|
|
493
|
+
mousedown: this.mousedown.bind(this),
|
|
494
|
+
mousemove: this.mousemove.bind(this),
|
|
495
|
+
mouseup: this.mouseup.bind(this),
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
this.bindOrUnbindEvent("bind");
|
|
499
|
+
}
|
|
500
|
+
finish() {
|
|
501
|
+
this.bindOrUnbindEvent("unbind");
|
|
502
|
+
}
|
|
503
|
+
bindOrUnbindEvent(type) {
|
|
504
|
+
const EventType =
|
|
505
|
+
type === "bind" ? "addEventListener" : "removeEventListener";
|
|
506
|
+
if (!this.#dom) return console.error("No DOM");
|
|
507
|
+
|
|
508
|
+
this.#dom[EventType]("mousedown", this.#eventFunction.mousedown);
|
|
509
|
+
document[EventType]("mousemove", this.#eventFunction.mousemove);
|
|
510
|
+
document[EventType]("mouseup", this.#eventFunction.mouseup);
|
|
511
|
+
}
|
|
512
|
+
alterLocation() {
|
|
513
|
+
if (!this.#dom) return console.error("No DOM");
|
|
514
|
+
if (this.#limit) {
|
|
515
|
+
this.#top = Math.min(this.#top, this.#limit.max.top);
|
|
516
|
+
this.#top = Math.max(this.#top, this.#limit.min.top);
|
|
517
|
+
this.#left = Math.min(this.#left, this.#limit.max.left);
|
|
518
|
+
this.#left = Math.max(this.#left, this.#limit.min.left);
|
|
519
|
+
}
|
|
520
|
+
this.#dom.style.setProperty("--top", this.#top + "px");
|
|
521
|
+
this.#dom.style.setProperty("--left", this.#left + "px");
|
|
522
|
+
}
|
|
523
|
+
mousedown(event) {
|
|
524
|
+
if (!this.#dom) return console.error("No DOM");
|
|
525
|
+
if (this.#dragDom && event.target != this.#dragDom) return;
|
|
526
|
+
document.body.classList.add("no-select");
|
|
527
|
+
|
|
528
|
+
this.#isAllowed = true;
|
|
529
|
+
const clientRect = this.#dom.getBoundingClientRect();
|
|
530
|
+
|
|
531
|
+
const { pageX, pageY } = event;
|
|
532
|
+
this.#pageX = pageX;
|
|
533
|
+
this.#pageY = pageY;
|
|
534
|
+
this.#top = clientRect.y;
|
|
535
|
+
this.#left = clientRect.x;
|
|
536
|
+
}
|
|
537
|
+
mousemove(event) {
|
|
538
|
+
const { pageX, pageY } = event;
|
|
539
|
+
if (this.#isAllowed) {
|
|
540
|
+
this.#top += pageY - this.#pageY;
|
|
541
|
+
this.#left += pageX - this.#pageX;
|
|
542
|
+
this.#pageX = pageX;
|
|
543
|
+
this.#pageY = pageY;
|
|
544
|
+
|
|
545
|
+
this.alterLocation();
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
mouseup() {
|
|
549
|
+
if (this.#isAllowed) {
|
|
550
|
+
this.#isAllowed = false;
|
|
551
|
+
document.body.classList.remove("no-select");
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/** 局部拖拽 计算位置距离/百分比 */
|
|
557
|
+
export class LocalDrag {
|
|
558
|
+
#parentDom = null;
|
|
559
|
+
#isAllowed = false;
|
|
560
|
+
#eventFunction = {};
|
|
561
|
+
#clientRectX = 0;
|
|
562
|
+
#clientRectY = 0;
|
|
563
|
+
#top = 0;
|
|
564
|
+
#left = 0;
|
|
565
|
+
#limit;
|
|
566
|
+
#update_move;
|
|
567
|
+
#update_up;
|
|
568
|
+
|
|
569
|
+
init(parentDom, options = {}) {
|
|
570
|
+
this.#parentDom = parentDom;
|
|
571
|
+
this.#limit = options.limit;
|
|
572
|
+
this.#update_move = options.update_move;
|
|
573
|
+
this.#update_up = options.update_up;
|
|
574
|
+
this.#eventFunction = {
|
|
575
|
+
mousedown: this.mousedown.bind(this),
|
|
576
|
+
mousemove: this.mousemove.bind(this),
|
|
577
|
+
mouseup: this.mouseup.bind(this),
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
this.bindOrUnbindEvent("bind");
|
|
581
|
+
}
|
|
582
|
+
finish() {
|
|
583
|
+
this.bindOrUnbindEvent("unbind");
|
|
584
|
+
}
|
|
585
|
+
bindOrUnbindEvent(type) {
|
|
586
|
+
const EventType =
|
|
587
|
+
type === "bind" ? "addEventListener" : "removeEventListener";
|
|
588
|
+
if (!this.#parentDom) return window.customize_error("No DOM");
|
|
589
|
+
|
|
590
|
+
this.#parentDom[EventType]("mousedown", this.#eventFunction.mousedown);
|
|
591
|
+
document[EventType]("mousemove", this.#eventFunction.mousemove);
|
|
592
|
+
document[EventType]("mouseup", this.#eventFunction.mouseup);
|
|
593
|
+
}
|
|
594
|
+
updateValue() {
|
|
595
|
+
const value = {
|
|
596
|
+
top: this.#top,
|
|
597
|
+
left: this.#left,
|
|
598
|
+
};
|
|
599
|
+
if (this.#limit) {
|
|
600
|
+
const v = (type) =>
|
|
601
|
+
this.#limit
|
|
602
|
+
? (value[type] - this.#limit.min[type]) /
|
|
603
|
+
(this.#limit.max[type] - this.#limit.min[type])
|
|
604
|
+
: 0;
|
|
605
|
+
|
|
606
|
+
value.percentage = {
|
|
607
|
+
top: v("top") || 0,
|
|
608
|
+
left: v("left") || 0,
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
return value;
|
|
612
|
+
}
|
|
613
|
+
alterLocation() {
|
|
614
|
+
if (!this.#parentDom) return window.customize_error("No DOM");
|
|
615
|
+
if (this.#limit) {
|
|
616
|
+
this.#top = Math.min(this.#top, this.#limit.max.top);
|
|
617
|
+
this.#top = Math.max(this.#top, this.#limit.min.top);
|
|
618
|
+
this.#left = Math.min(this.#left, this.#limit.max.left);
|
|
619
|
+
this.#left = Math.max(this.#left, this.#limit.min.left);
|
|
620
|
+
}
|
|
621
|
+
if (this.#update_move) this.#update_move(this.updateValue());
|
|
622
|
+
|
|
623
|
+
this.#parentDom.style.setProperty("--top", this.#top + "px");
|
|
624
|
+
this.#parentDom.style.setProperty("--left", this.#left + "px");
|
|
625
|
+
}
|
|
626
|
+
mousedown(event) {
|
|
627
|
+
if (!this.#parentDom) return window.customize_error("No DOM");
|
|
628
|
+
document.body.classList.add("no-select");
|
|
629
|
+
|
|
630
|
+
this.#isAllowed = true;
|
|
631
|
+
const clientRect = this.#parentDom.getBoundingClientRect();
|
|
632
|
+
this.#clientRectY = clientRect.y;
|
|
633
|
+
this.#clientRectX = clientRect.x;
|
|
634
|
+
|
|
635
|
+
const { pageX, pageY } = event;
|
|
636
|
+
this.#top = pageY - this.#clientRectY;
|
|
637
|
+
this.#left = pageX - this.#clientRectX;
|
|
638
|
+
|
|
639
|
+
this.alterLocation();
|
|
640
|
+
}
|
|
641
|
+
mousemove(event) {
|
|
642
|
+
const { pageX, pageY } = event;
|
|
643
|
+
if (this.#isAllowed) {
|
|
644
|
+
this.#top = pageY - this.#clientRectY;
|
|
645
|
+
this.#left = pageX - this.#clientRectX;
|
|
646
|
+
this.alterLocation();
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
mouseup() {
|
|
650
|
+
if (this.#isAllowed) {
|
|
651
|
+
this.#isAllowed = false;
|
|
652
|
+
document.body.classList.remove("no-select");
|
|
653
|
+
if (this.#update_up) this.#update_up(this.updateValue());
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
package/lib/Utility.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ExtractParameters } from "./Index";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* 非null | undefined判断
|
|
3
5
|
* @param value any
|
|
@@ -40,7 +42,7 @@ export function _ConvertToPercentage(
|
|
|
40
42
|
export function _WaitForCondition(
|
|
41
43
|
conditionChecker: () => boolean,
|
|
42
44
|
timeoutMillis: number
|
|
43
|
-
): Promise
|
|
45
|
+
): Promise<"完成" | "超时">;
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
48
|
* 排除子串
|
|
@@ -104,27 +106,30 @@ export function _ReadFile(src: string): Promise<string>;
|
|
|
104
106
|
|
|
105
107
|
/**
|
|
106
108
|
* 下载文件
|
|
107
|
-
* @param {
|
|
108
|
-
* @param {
|
|
109
|
+
* @param {string} href 文件路径
|
|
110
|
+
* @param {string} fileName 导出文件名
|
|
109
111
|
*/
|
|
110
112
|
export function _DownloadFile(href: string, fileName?: string): void;
|
|
111
113
|
|
|
112
114
|
/**
|
|
113
115
|
* 获取帧率
|
|
114
|
-
* @param {
|
|
116
|
+
* @param {(fps , frameTime)=>void} callback callback( 帧率 , 每帧时间 )
|
|
115
117
|
* @param {Number} referenceNode 参考节点数量
|
|
116
118
|
*/
|
|
117
119
|
export function _GetFrameRate(
|
|
118
|
-
callback:
|
|
119
|
-
referenceNode: number
|
|
120
|
+
callback: (fps: number, frameTime: number) => void,
|
|
121
|
+
referenceNode: number
|
|
120
122
|
): void;
|
|
121
123
|
|
|
122
124
|
/**
|
|
123
125
|
* 进度
|
|
124
|
-
* @param {
|
|
126
|
+
* @param {(schedule)=>void} callback callback( 进度百分比 )
|
|
125
127
|
* @param {Number} TIME 总时长
|
|
126
128
|
*/
|
|
127
|
-
export function _Schedule(
|
|
129
|
+
export function _Schedule(
|
|
130
|
+
callback: (schedule: number) => void,
|
|
131
|
+
TIME: number
|
|
132
|
+
): void;
|
|
128
133
|
|
|
129
134
|
/**
|
|
130
135
|
* 格式化数字,给数字加上千位分隔符。
|
|
@@ -150,3 +155,50 @@ export function _ConvertToCamelCase(
|
|
|
150
155
|
str: string,
|
|
151
156
|
isRemoveDelimiter?: boolean
|
|
152
157
|
): string;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 创建文件并下载
|
|
161
|
+
* @param {BlobPart[]} content 文件内容
|
|
162
|
+
* @param {string} fileName 文件名称
|
|
163
|
+
* @param {BlobPropertyBag} options Blob 配置
|
|
164
|
+
*/
|
|
165
|
+
export function _CreateAndDownloadFile(
|
|
166
|
+
content: BlobPart[],
|
|
167
|
+
fileName: string,
|
|
168
|
+
options?: BlobPropertyBag
|
|
169
|
+
): void;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 获取url参数
|
|
173
|
+
* @param {string} url
|
|
174
|
+
* @returns {Object}
|
|
175
|
+
*/
|
|
176
|
+
export function _GetQueryParams(url: string): void;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 生成uuid
|
|
180
|
+
* @returns {string}
|
|
181
|
+
*/
|
|
182
|
+
export function _GenerateUUID(): string;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 防抖
|
|
186
|
+
* @param {Function} fn
|
|
187
|
+
* @param {number} delay
|
|
188
|
+
* @returns {Function}
|
|
189
|
+
*/
|
|
190
|
+
export function _Debounce<T extends Function>(
|
|
191
|
+
fn: T,
|
|
192
|
+
delay: number
|
|
193
|
+
): (...args: ExtractParameters<T>) => void;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 节流
|
|
197
|
+
* @param {Function} fn
|
|
198
|
+
* @param {number} delay
|
|
199
|
+
* @returns {Function}
|
|
200
|
+
*/
|
|
201
|
+
export function _Throttle<T extends Function>(
|
|
202
|
+
fn: T,
|
|
203
|
+
delay: number
|
|
204
|
+
): (...args: ExtractParameters<T>) => void;
|
package/lib/Utility.js
CHANGED
|
@@ -228,32 +228,32 @@ export function _DownloadFile(href, fileName) {
|
|
|
228
228
|
|
|
229
229
|
/**
|
|
230
230
|
* 获取帧率
|
|
231
|
-
* @param {
|
|
231
|
+
* @param {(fps , frameTime)=>void} callback callback( 帧率 , 每帧时间 )
|
|
232
232
|
* @param {Number} referenceNode 参考节点数量
|
|
233
233
|
*/
|
|
234
234
|
export function _GetFrameRate(callback, referenceNode = 10) {
|
|
235
235
|
let t,
|
|
236
|
-
|
|
237
|
-
function loop(
|
|
238
|
-
if (
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
236
|
+
l = referenceNode;
|
|
237
|
+
function loop() {
|
|
238
|
+
if (l > 0) {
|
|
239
|
+
l--;
|
|
240
|
+
requestAnimationFrame(loop);
|
|
241
|
+
} else {
|
|
242
|
+
const time = new Date() - t;
|
|
243
|
+
const frameTime = time / referenceNode;
|
|
244
|
+
const fps = 1000 / frameTime;
|
|
245
|
+
callback(Number(fps.toFixed(2)), Number(frameTime.toFixed(2)));
|
|
247
246
|
}
|
|
248
|
-
t = time;
|
|
249
|
-
requestAnimationFrame(loop);
|
|
250
247
|
}
|
|
251
|
-
requestAnimationFrame(
|
|
248
|
+
requestAnimationFrame(() => {
|
|
249
|
+
t = new Date() - 0;
|
|
250
|
+
loop();
|
|
251
|
+
});
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
/**
|
|
255
255
|
* 进度
|
|
256
|
-
* @param {
|
|
256
|
+
* @param {(schedule)=>void} callback callback( 进度百分比 )
|
|
257
257
|
* @param {Number} TIME 总时长
|
|
258
258
|
*/
|
|
259
259
|
export function _Schedule(callback, TIME = 500) {
|
|
@@ -302,3 +302,82 @@ export function _ConvertToCamelCase(str, isRemoveDelimiter) {
|
|
|
302
302
|
if (isRemoveDelimiter) return str.replace(/[^a-zA-Z]+/g, "");
|
|
303
303
|
return str;
|
|
304
304
|
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* 创建文件并下载
|
|
308
|
+
* @param {BlobPart[]} content 文件内容
|
|
309
|
+
* @param {string} fileName 文件名称
|
|
310
|
+
* @param {BlobPropertyBag} options Blob 配置
|
|
311
|
+
*/
|
|
312
|
+
export function _CreateAndDownloadFile(content, fileName, options) {
|
|
313
|
+
if (!options) {
|
|
314
|
+
let type = fileName.replace(/^[^.]+./, "");
|
|
315
|
+
type = type == fileName ? "text/plain" : "application/" + type;
|
|
316
|
+
options = { type };
|
|
317
|
+
}
|
|
318
|
+
const bolb = new Blob(content, options);
|
|
319
|
+
// 创建一个 URL,该 URL 可以用于在浏览器中引用 Blob 对象(例如,在 <a> 标签的 href 属性中)
|
|
320
|
+
const url = URL.createObjectURL(bolb);
|
|
321
|
+
// 你可以创建一个链接来下载这个 Blob 对象
|
|
322
|
+
const downloadLink = document.createElement("a");
|
|
323
|
+
downloadLink.href = url;
|
|
324
|
+
downloadLink.download = fileName; // 设置下载文件的名称
|
|
325
|
+
document.body.appendChild(downloadLink); // 添加到文档中
|
|
326
|
+
downloadLink.click(); // 模拟点击以开始下载
|
|
327
|
+
document.body.removeChild(downloadLink); // 然后从文档中移除
|
|
328
|
+
// 最后,别忘了撤销 Blob 对象的 URL,以释放资源
|
|
329
|
+
URL.revokeObjectURL(url);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* 获取url参数
|
|
334
|
+
* @param {string} url
|
|
335
|
+
* @returns {Object}
|
|
336
|
+
*/
|
|
337
|
+
export function _GetQueryParams(url) {
|
|
338
|
+
return Object.fromEntries(new URL(url).searchParams);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* 生成uuid
|
|
343
|
+
* @returns {string}
|
|
344
|
+
*/
|
|
345
|
+
export function _GenerateUUID() {
|
|
346
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
347
|
+
const r = (Math.random() * 16) | 0; // 随机生成一个0到15的数
|
|
348
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8; // 对于'y'位, v = (r & 0x3 | 0x8) 确保变体正确
|
|
349
|
+
return v.toString(16); // 将数字转换为16进制
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* 防抖
|
|
355
|
+
* @param {Function} fn
|
|
356
|
+
* @param {number} delay
|
|
357
|
+
* @returns {Function}
|
|
358
|
+
*/
|
|
359
|
+
export function _Debounce(fn, delay) {
|
|
360
|
+
let timeoutId;
|
|
361
|
+
return function (...args) {
|
|
362
|
+
clearTimeout(timeoutId);
|
|
363
|
+
timeoutId = setTimeout(() => fn.apply(this, args), delay);
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* 节流
|
|
369
|
+
* @param {Function} fn
|
|
370
|
+
* @param {number} delay
|
|
371
|
+
* @returns {Function}
|
|
372
|
+
*/
|
|
373
|
+
export function _Throttle(fn, delay) {
|
|
374
|
+
let timer;
|
|
375
|
+
return function (...args) {
|
|
376
|
+
if (!timer) {
|
|
377
|
+
timer = setTimeout(() => {
|
|
378
|
+
fn.apply(this, args);
|
|
379
|
+
timer = null;
|
|
380
|
+
}, delay);
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
}
|
package/lib/index.css
ADDED
package/lib/index.less
ADDED
package/lib/test.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/** 用于测试 js / ts 功能实现及类型是否正确 */
|