sculp-js 1.7.1 → 1.7.2
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/cjs/array.js +1 -1
- package/lib/cjs/async.js +1 -1
- package/lib/cjs/base64.js +1 -1
- package/lib/cjs/clipboard.js +1 -1
- package/lib/cjs/cookie.js +1 -1
- package/lib/cjs/date.js +1 -1
- package/lib/cjs/dom.js +1 -1
- package/lib/cjs/download.js +1 -1
- package/lib/cjs/easing.js +1 -1
- package/lib/cjs/file.js +1 -1
- package/lib/cjs/func.js +1 -1
- package/lib/cjs/index.js +1 -1
- package/lib/cjs/math.js +1 -1
- package/lib/cjs/number.js +1 -1
- package/lib/cjs/object.js +61 -24
- package/lib/cjs/path.js +1 -1
- package/lib/cjs/qs.js +1 -1
- package/lib/cjs/random.js +1 -1
- package/lib/cjs/string.js +1 -1
- package/lib/cjs/tooltip.js +1 -1
- package/lib/cjs/tree.js +30 -10
- package/lib/cjs/type.js +1 -1
- package/lib/cjs/unique.js +1 -1
- package/lib/cjs/url.js +1 -1
- package/lib/cjs/validator.js +1 -1
- package/lib/cjs/variable.js +1 -1
- package/lib/cjs/watermark.js +1 -1
- package/lib/cjs/we-decode.js +1 -1
- package/lib/es/array.js +1 -1
- package/lib/es/async.js +1 -1
- package/lib/es/base64.js +1 -1
- package/lib/es/clipboard.js +1 -1
- package/lib/es/cookie.js +1 -1
- package/lib/es/date.js +1 -1
- package/lib/es/dom.js +1 -1
- package/lib/es/download.js +1 -1
- package/lib/es/easing.js +1 -1
- package/lib/es/file.js +1 -1
- package/lib/es/func.js +1 -1
- package/lib/es/index.js +1 -1
- package/lib/es/math.js +1 -1
- package/lib/es/number.js +1 -1
- package/lib/es/object.js +61 -24
- package/lib/es/path.js +1 -1
- package/lib/es/qs.js +1 -1
- package/lib/es/random.js +1 -1
- package/lib/es/string.js +1 -1
- package/lib/es/tooltip.js +1 -1
- package/lib/es/tree.js +30 -10
- package/lib/es/type.js +1 -1
- package/lib/es/unique.js +1 -1
- package/lib/es/url.js +1 -1
- package/lib/es/validator.js +1 -1
- package/lib/es/variable.js +1 -1
- package/lib/es/watermark.js +1 -1
- package/lib/es/we-decode.js +1 -1
- package/lib/index.d.ts +29 -9
- package/lib/umd/index.js +89 -33
- package/package.json +1 -1
package/lib/cjs/array.js
CHANGED
package/lib/cjs/async.js
CHANGED
package/lib/cjs/base64.js
CHANGED
package/lib/cjs/clipboard.js
CHANGED
package/lib/cjs/cookie.js
CHANGED
package/lib/cjs/date.js
CHANGED
package/lib/cjs/dom.js
CHANGED
package/lib/cjs/download.js
CHANGED
package/lib/cjs/easing.js
CHANGED
package/lib/cjs/file.js
CHANGED
package/lib/cjs/func.js
CHANGED
package/lib/cjs/index.js
CHANGED
package/lib/cjs/math.js
CHANGED
package/lib/cjs/number.js
CHANGED
package/lib/cjs/object.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* sculp-js v1.7.
|
|
2
|
+
* sculp-js v1.7.2
|
|
3
3
|
* (c) 2023-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -83,7 +83,7 @@ function objectPick(obj, keys) {
|
|
|
83
83
|
return obj2;
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
|
-
*
|
|
86
|
+
* 对象去除
|
|
87
87
|
* @param {O} obj
|
|
88
88
|
* @param {K} keys
|
|
89
89
|
* @returns {Pick<O, ArrayElements<K>>}
|
|
@@ -198,12 +198,16 @@ function objectGet(obj, path, strict = false) {
|
|
|
198
198
|
}
|
|
199
199
|
/**
|
|
200
200
|
* 深拷贝堪称完全体 即:任何类型的数据都会被深拷贝
|
|
201
|
+
*
|
|
202
|
+
* 包含对null、原始值、对象循环引用的处理
|
|
203
|
+
*
|
|
204
|
+
* 对Map、Set、ArrayBuffer、Date、RegExp、Array、Object及原型链属性方法执行深拷贝
|
|
201
205
|
* @param {T} source
|
|
202
206
|
* @param {WeakMap} map
|
|
203
207
|
* @returns {T}
|
|
204
208
|
*/
|
|
205
209
|
function cloneDeep(source, map = new WeakMap()) {
|
|
206
|
-
//
|
|
210
|
+
// 处理原始类型和 null/undefined
|
|
207
211
|
if (source === null || typeof source !== 'object') {
|
|
208
212
|
return source;
|
|
209
213
|
}
|
|
@@ -211,28 +215,33 @@ function cloneDeep(source, map = new WeakMap()) {
|
|
|
211
215
|
if (map.has(source)) {
|
|
212
216
|
return map.get(source);
|
|
213
217
|
}
|
|
214
|
-
// 处理
|
|
218
|
+
// 处理 ArrayBuffer
|
|
219
|
+
if (source instanceof ArrayBuffer) {
|
|
220
|
+
const copy = new ArrayBuffer(source.byteLength);
|
|
221
|
+
new Uint8Array(copy).set(new Uint8Array(source));
|
|
222
|
+
map.set(source, copy);
|
|
223
|
+
return copy;
|
|
224
|
+
}
|
|
225
|
+
// 处理 DataView 和 TypedArray (Uint8Array 等)
|
|
226
|
+
if (ArrayBuffer.isView(source)) {
|
|
227
|
+
const constructor = source.constructor;
|
|
228
|
+
const bufferCopy = cloneDeep(source.buffer, map);
|
|
229
|
+
return new constructor(bufferCopy, source.byteOffset, source.length);
|
|
230
|
+
}
|
|
231
|
+
// 处理 Date 对象
|
|
215
232
|
if (source instanceof Date) {
|
|
216
233
|
const copy = new Date(source.getTime());
|
|
217
234
|
map.set(source, copy);
|
|
218
235
|
return copy;
|
|
219
236
|
}
|
|
220
|
-
// 处理 RegExp
|
|
237
|
+
// 处理 RegExp 对象
|
|
221
238
|
if (source instanceof RegExp) {
|
|
222
239
|
const copy = new RegExp(source.source, source.flags);
|
|
240
|
+
copy.lastIndex = source.lastIndex; // 保留匹配状态
|
|
223
241
|
map.set(source, copy);
|
|
224
242
|
return copy;
|
|
225
243
|
}
|
|
226
|
-
//
|
|
227
|
-
if (Array.isArray(source)) {
|
|
228
|
-
const copy = [];
|
|
229
|
-
map.set(source, copy);
|
|
230
|
-
for (const item of source) {
|
|
231
|
-
copy.push(cloneDeep(item, map));
|
|
232
|
-
}
|
|
233
|
-
return copy;
|
|
234
|
-
}
|
|
235
|
-
// 处理 Map 类型
|
|
244
|
+
// 处理 Map
|
|
236
245
|
if (source instanceof Map) {
|
|
237
246
|
const copy = new Map();
|
|
238
247
|
map.set(source, copy);
|
|
@@ -241,7 +250,7 @@ function cloneDeep(source, map = new WeakMap()) {
|
|
|
241
250
|
});
|
|
242
251
|
return copy;
|
|
243
252
|
}
|
|
244
|
-
// 处理 Set
|
|
253
|
+
// 处理 Set
|
|
245
254
|
if (source instanceof Set) {
|
|
246
255
|
const copy = new Set();
|
|
247
256
|
map.set(source, copy);
|
|
@@ -250,19 +259,47 @@ function cloneDeep(source, map = new WeakMap()) {
|
|
|
250
259
|
});
|
|
251
260
|
return copy;
|
|
252
261
|
}
|
|
253
|
-
//
|
|
254
|
-
if (source
|
|
255
|
-
const copy =
|
|
256
|
-
new Uint8Array(copy).set(new Uint8Array(source));
|
|
262
|
+
// 处理数组 (包含稀疏数组)
|
|
263
|
+
if (Array.isArray(source)) {
|
|
264
|
+
const copy = Array.from({ length: source.length });
|
|
257
265
|
map.set(source, copy);
|
|
266
|
+
// 克隆所有有效索引
|
|
267
|
+
for (let i = 0; i < source.length; i++) {
|
|
268
|
+
if (i in source) {
|
|
269
|
+
// 保留空位
|
|
270
|
+
copy[i] = cloneDeep(source[i], map);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// 克隆数组的自定义属性
|
|
274
|
+
const descriptors = Object.getOwnPropertyDescriptors(source);
|
|
275
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
276
|
+
Object.defineProperty(copy, key, {
|
|
277
|
+
...descriptors[key],
|
|
278
|
+
value: cloneDeep(descriptors[key].value, map)
|
|
279
|
+
});
|
|
280
|
+
}
|
|
258
281
|
return copy;
|
|
259
282
|
}
|
|
260
|
-
//
|
|
283
|
+
// 处理普通对象和类实例
|
|
261
284
|
const copy = Object.create(Object.getPrototypeOf(source));
|
|
262
285
|
map.set(source, copy);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
286
|
+
const descriptors = Object.getOwnPropertyDescriptors(source);
|
|
287
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
288
|
+
const descriptor = descriptors[key];
|
|
289
|
+
if ('value' in descriptor) {
|
|
290
|
+
// 克隆数据属性
|
|
291
|
+
descriptor.value = cloneDeep(descriptor.value, map);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
// 处理访问器属性 (getter/setter)
|
|
295
|
+
if (descriptor.get) {
|
|
296
|
+
descriptor.get = cloneDeep(descriptor.get, map);
|
|
297
|
+
}
|
|
298
|
+
if (descriptor.set) {
|
|
299
|
+
descriptor.set = cloneDeep(descriptor.set, map);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
Object.defineProperty(copy, key, descriptor);
|
|
266
303
|
}
|
|
267
304
|
return copy;
|
|
268
305
|
}
|
package/lib/cjs/path.js
CHANGED
package/lib/cjs/qs.js
CHANGED
package/lib/cjs/random.js
CHANGED
package/lib/cjs/string.js
CHANGED
package/lib/cjs/tooltip.js
CHANGED
package/lib/cjs/tree.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* sculp-js v1.7.
|
|
2
|
+
* sculp-js v1.7.2
|
|
3
3
|
* (c) 2023-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
var object = require('./object.js');
|
|
10
|
+
var type = require('./type.js');
|
|
10
11
|
|
|
11
12
|
const defaultFieldOptions = { keyField: 'key', childField: 'children', pidField: 'pid' };
|
|
12
13
|
const defaultSearchTreeOptions = {
|
|
13
14
|
childField: 'children',
|
|
14
15
|
nameField: 'name',
|
|
15
|
-
|
|
16
|
+
removeEmptyChild: false,
|
|
17
|
+
ignoreCase: true
|
|
16
18
|
};
|
|
17
19
|
/**
|
|
18
20
|
* 深度优先遍历函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
@@ -69,7 +71,9 @@ function forEachDeep(tree, iterator, children = 'children', isReverse = false) {
|
|
|
69
71
|
walk(tree, null);
|
|
70
72
|
}
|
|
71
73
|
/**
|
|
72
|
-
* 深度优先遍历的Map函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
74
|
+
* 创建一个新数组, 深度优先遍历的Map函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
75
|
+
*
|
|
76
|
+
* 可遍历任何带有 length 属性和数字键的类数组对象
|
|
73
77
|
* @param {ArrayLike<V>} tree 树形数据
|
|
74
78
|
* @param {Function} iterator 迭代函数, 返回值为true时continue, 返回值为false时break
|
|
75
79
|
* @param {string} children 定制子元素的key
|
|
@@ -305,20 +309,36 @@ function flatTree(treeList, options = defaultFieldOptions) {
|
|
|
305
309
|
}
|
|
306
310
|
/**
|
|
307
311
|
* 模糊搜索函数,返回包含搜索字符的节点及其祖先节点, 适用于树型组件的字符过滤功能
|
|
308
|
-
*
|
|
309
|
-
*
|
|
312
|
+
* 以下搜索条件二选一,按先后优先级处理:
|
|
313
|
+
* 1. 过滤函数filter, 返回true/false
|
|
314
|
+
* 2. 匹配关键词,支持是否启用忽略大小写来判断
|
|
315
|
+
*
|
|
316
|
+
* 有以下特性:
|
|
317
|
+
* 1. 可配置removeEmptyChild字段,来决定是否移除搜索结果中的空children字段
|
|
318
|
+
* 2. 若无任何过滤条件或keyword模式匹配且keyword为空串,返回原对象;其他情况返回新数组
|
|
319
|
+
* @param {V[]} nodes
|
|
320
|
+
* @param {IFilterCondition} filterCondition
|
|
310
321
|
* @param {ISearchTreeOpts} options
|
|
311
|
-
* @returns {
|
|
322
|
+
* @returns {V[]}
|
|
312
323
|
*/
|
|
313
|
-
function fuzzySearchTree(nodes,
|
|
324
|
+
function fuzzySearchTree(nodes, filterCondition, options = defaultSearchTreeOptions) {
|
|
325
|
+
if (!type.objectHas(filterCondition, 'filter') &&
|
|
326
|
+
(!type.objectHas(filterCondition, 'keyword') || type.isEmpty(filterCondition.keyword))) {
|
|
327
|
+
return nodes;
|
|
328
|
+
}
|
|
314
329
|
const result = [];
|
|
315
330
|
for (const node of nodes) {
|
|
316
331
|
// 递归检查子节点是否匹配
|
|
317
332
|
const matchedChildren = node[options.childField] && node[options.childField].length > 0
|
|
318
|
-
? fuzzySearchTree(node[options.childField] || [],
|
|
333
|
+
? fuzzySearchTree(node[options.childField] || [], filterCondition, options)
|
|
319
334
|
: [];
|
|
320
335
|
// 检查当前节点是否匹配或者有匹配的子节点
|
|
321
|
-
if (
|
|
336
|
+
if ((type.objectHas(filterCondition, 'filter')
|
|
337
|
+
? filterCondition.filter(node)
|
|
338
|
+
: !options.ignoreCase
|
|
339
|
+
? node[options.nameField].includes(filterCondition.keyword)
|
|
340
|
+
: node[options.nameField].toLowerCase().includes(filterCondition.keyword.toLowerCase())) ||
|
|
341
|
+
matchedChildren.length > 0) {
|
|
322
342
|
// 将当前节点加入结果中
|
|
323
343
|
if (node[options.childField]) {
|
|
324
344
|
if (matchedChildren.length > 0) {
|
|
@@ -327,7 +347,7 @@ function fuzzySearchTree(nodes, query, options = defaultSearchTreeOptions) {
|
|
|
327
347
|
[options.childField]: matchedChildren // 包含匹配的子节点
|
|
328
348
|
});
|
|
329
349
|
}
|
|
330
|
-
else if (options.
|
|
350
|
+
else if (options.removeEmptyChild) {
|
|
331
351
|
node[options.childField] && delete node[options.childField];
|
|
332
352
|
result.push({
|
|
333
353
|
...node
|
package/lib/cjs/type.js
CHANGED
package/lib/cjs/unique.js
CHANGED
package/lib/cjs/url.js
CHANGED
package/lib/cjs/validator.js
CHANGED
package/lib/cjs/variable.js
CHANGED
package/lib/cjs/watermark.js
CHANGED
package/lib/cjs/we-decode.js
CHANGED
package/lib/es/array.js
CHANGED
package/lib/es/async.js
CHANGED
package/lib/es/base64.js
CHANGED
package/lib/es/clipboard.js
CHANGED
package/lib/es/cookie.js
CHANGED
package/lib/es/date.js
CHANGED
package/lib/es/dom.js
CHANGED
package/lib/es/download.js
CHANGED
package/lib/es/easing.js
CHANGED
package/lib/es/file.js
CHANGED
package/lib/es/func.js
CHANGED
package/lib/es/index.js
CHANGED
package/lib/es/math.js
CHANGED
package/lib/es/number.js
CHANGED
package/lib/es/object.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* sculp-js v1.7.
|
|
2
|
+
* sculp-js v1.7.2
|
|
3
3
|
* (c) 2023-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -81,7 +81,7 @@ function objectPick(obj, keys) {
|
|
|
81
81
|
return obj2;
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
84
|
-
*
|
|
84
|
+
* 对象去除
|
|
85
85
|
* @param {O} obj
|
|
86
86
|
* @param {K} keys
|
|
87
87
|
* @returns {Pick<O, ArrayElements<K>>}
|
|
@@ -196,12 +196,16 @@ function objectGet(obj, path, strict = false) {
|
|
|
196
196
|
}
|
|
197
197
|
/**
|
|
198
198
|
* 深拷贝堪称完全体 即:任何类型的数据都会被深拷贝
|
|
199
|
+
*
|
|
200
|
+
* 包含对null、原始值、对象循环引用的处理
|
|
201
|
+
*
|
|
202
|
+
* 对Map、Set、ArrayBuffer、Date、RegExp、Array、Object及原型链属性方法执行深拷贝
|
|
199
203
|
* @param {T} source
|
|
200
204
|
* @param {WeakMap} map
|
|
201
205
|
* @returns {T}
|
|
202
206
|
*/
|
|
203
207
|
function cloneDeep(source, map = new WeakMap()) {
|
|
204
|
-
//
|
|
208
|
+
// 处理原始类型和 null/undefined
|
|
205
209
|
if (source === null || typeof source !== 'object') {
|
|
206
210
|
return source;
|
|
207
211
|
}
|
|
@@ -209,28 +213,33 @@ function cloneDeep(source, map = new WeakMap()) {
|
|
|
209
213
|
if (map.has(source)) {
|
|
210
214
|
return map.get(source);
|
|
211
215
|
}
|
|
212
|
-
// 处理
|
|
216
|
+
// 处理 ArrayBuffer
|
|
217
|
+
if (source instanceof ArrayBuffer) {
|
|
218
|
+
const copy = new ArrayBuffer(source.byteLength);
|
|
219
|
+
new Uint8Array(copy).set(new Uint8Array(source));
|
|
220
|
+
map.set(source, copy);
|
|
221
|
+
return copy;
|
|
222
|
+
}
|
|
223
|
+
// 处理 DataView 和 TypedArray (Uint8Array 等)
|
|
224
|
+
if (ArrayBuffer.isView(source)) {
|
|
225
|
+
const constructor = source.constructor;
|
|
226
|
+
const bufferCopy = cloneDeep(source.buffer, map);
|
|
227
|
+
return new constructor(bufferCopy, source.byteOffset, source.length);
|
|
228
|
+
}
|
|
229
|
+
// 处理 Date 对象
|
|
213
230
|
if (source instanceof Date) {
|
|
214
231
|
const copy = new Date(source.getTime());
|
|
215
232
|
map.set(source, copy);
|
|
216
233
|
return copy;
|
|
217
234
|
}
|
|
218
|
-
// 处理 RegExp
|
|
235
|
+
// 处理 RegExp 对象
|
|
219
236
|
if (source instanceof RegExp) {
|
|
220
237
|
const copy = new RegExp(source.source, source.flags);
|
|
238
|
+
copy.lastIndex = source.lastIndex; // 保留匹配状态
|
|
221
239
|
map.set(source, copy);
|
|
222
240
|
return copy;
|
|
223
241
|
}
|
|
224
|
-
//
|
|
225
|
-
if (Array.isArray(source)) {
|
|
226
|
-
const copy = [];
|
|
227
|
-
map.set(source, copy);
|
|
228
|
-
for (const item of source) {
|
|
229
|
-
copy.push(cloneDeep(item, map));
|
|
230
|
-
}
|
|
231
|
-
return copy;
|
|
232
|
-
}
|
|
233
|
-
// 处理 Map 类型
|
|
242
|
+
// 处理 Map
|
|
234
243
|
if (source instanceof Map) {
|
|
235
244
|
const copy = new Map();
|
|
236
245
|
map.set(source, copy);
|
|
@@ -239,7 +248,7 @@ function cloneDeep(source, map = new WeakMap()) {
|
|
|
239
248
|
});
|
|
240
249
|
return copy;
|
|
241
250
|
}
|
|
242
|
-
// 处理 Set
|
|
251
|
+
// 处理 Set
|
|
243
252
|
if (source instanceof Set) {
|
|
244
253
|
const copy = new Set();
|
|
245
254
|
map.set(source, copy);
|
|
@@ -248,19 +257,47 @@ function cloneDeep(source, map = new WeakMap()) {
|
|
|
248
257
|
});
|
|
249
258
|
return copy;
|
|
250
259
|
}
|
|
251
|
-
//
|
|
252
|
-
if (source
|
|
253
|
-
const copy =
|
|
254
|
-
new Uint8Array(copy).set(new Uint8Array(source));
|
|
260
|
+
// 处理数组 (包含稀疏数组)
|
|
261
|
+
if (Array.isArray(source)) {
|
|
262
|
+
const copy = Array.from({ length: source.length });
|
|
255
263
|
map.set(source, copy);
|
|
264
|
+
// 克隆所有有效索引
|
|
265
|
+
for (let i = 0; i < source.length; i++) {
|
|
266
|
+
if (i in source) {
|
|
267
|
+
// 保留空位
|
|
268
|
+
copy[i] = cloneDeep(source[i], map);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// 克隆数组的自定义属性
|
|
272
|
+
const descriptors = Object.getOwnPropertyDescriptors(source);
|
|
273
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
274
|
+
Object.defineProperty(copy, key, {
|
|
275
|
+
...descriptors[key],
|
|
276
|
+
value: cloneDeep(descriptors[key].value, map)
|
|
277
|
+
});
|
|
278
|
+
}
|
|
256
279
|
return copy;
|
|
257
280
|
}
|
|
258
|
-
//
|
|
281
|
+
// 处理普通对象和类实例
|
|
259
282
|
const copy = Object.create(Object.getPrototypeOf(source));
|
|
260
283
|
map.set(source, copy);
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
284
|
+
const descriptors = Object.getOwnPropertyDescriptors(source);
|
|
285
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
286
|
+
const descriptor = descriptors[key];
|
|
287
|
+
if ('value' in descriptor) {
|
|
288
|
+
// 克隆数据属性
|
|
289
|
+
descriptor.value = cloneDeep(descriptor.value, map);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
// 处理访问器属性 (getter/setter)
|
|
293
|
+
if (descriptor.get) {
|
|
294
|
+
descriptor.get = cloneDeep(descriptor.get, map);
|
|
295
|
+
}
|
|
296
|
+
if (descriptor.set) {
|
|
297
|
+
descriptor.set = cloneDeep(descriptor.set, map);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
Object.defineProperty(copy, key, descriptor);
|
|
264
301
|
}
|
|
265
302
|
return copy;
|
|
266
303
|
}
|
package/lib/es/path.js
CHANGED
package/lib/es/qs.js
CHANGED
package/lib/es/random.js
CHANGED
package/lib/es/string.js
CHANGED
package/lib/es/tooltip.js
CHANGED
package/lib/es/tree.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* sculp-js v1.7.
|
|
2
|
+
* sculp-js v1.7.2
|
|
3
3
|
* (c) 2023-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { objectOmit } from './object.js';
|
|
8
|
+
import { objectHas, isEmpty } from './type.js';
|
|
8
9
|
|
|
9
10
|
const defaultFieldOptions = { keyField: 'key', childField: 'children', pidField: 'pid' };
|
|
10
11
|
const defaultSearchTreeOptions = {
|
|
11
12
|
childField: 'children',
|
|
12
13
|
nameField: 'name',
|
|
13
|
-
|
|
14
|
+
removeEmptyChild: false,
|
|
15
|
+
ignoreCase: true
|
|
14
16
|
};
|
|
15
17
|
/**
|
|
16
18
|
* 深度优先遍历函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
@@ -67,7 +69,9 @@ function forEachDeep(tree, iterator, children = 'children', isReverse = false) {
|
|
|
67
69
|
walk(tree, null);
|
|
68
70
|
}
|
|
69
71
|
/**
|
|
70
|
-
* 深度优先遍历的Map函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
72
|
+
* 创建一个新数组, 深度优先遍历的Map函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
73
|
+
*
|
|
74
|
+
* 可遍历任何带有 length 属性和数字键的类数组对象
|
|
71
75
|
* @param {ArrayLike<V>} tree 树形数据
|
|
72
76
|
* @param {Function} iterator 迭代函数, 返回值为true时continue, 返回值为false时break
|
|
73
77
|
* @param {string} children 定制子元素的key
|
|
@@ -303,20 +307,36 @@ function flatTree(treeList, options = defaultFieldOptions) {
|
|
|
303
307
|
}
|
|
304
308
|
/**
|
|
305
309
|
* 模糊搜索函数,返回包含搜索字符的节点及其祖先节点, 适用于树型组件的字符过滤功能
|
|
306
|
-
*
|
|
307
|
-
*
|
|
310
|
+
* 以下搜索条件二选一,按先后优先级处理:
|
|
311
|
+
* 1. 过滤函数filter, 返回true/false
|
|
312
|
+
* 2. 匹配关键词,支持是否启用忽略大小写来判断
|
|
313
|
+
*
|
|
314
|
+
* 有以下特性:
|
|
315
|
+
* 1. 可配置removeEmptyChild字段,来决定是否移除搜索结果中的空children字段
|
|
316
|
+
* 2. 若无任何过滤条件或keyword模式匹配且keyword为空串,返回原对象;其他情况返回新数组
|
|
317
|
+
* @param {V[]} nodes
|
|
318
|
+
* @param {IFilterCondition} filterCondition
|
|
308
319
|
* @param {ISearchTreeOpts} options
|
|
309
|
-
* @returns {
|
|
320
|
+
* @returns {V[]}
|
|
310
321
|
*/
|
|
311
|
-
function fuzzySearchTree(nodes,
|
|
322
|
+
function fuzzySearchTree(nodes, filterCondition, options = defaultSearchTreeOptions) {
|
|
323
|
+
if (!objectHas(filterCondition, 'filter') &&
|
|
324
|
+
(!objectHas(filterCondition, 'keyword') || isEmpty(filterCondition.keyword))) {
|
|
325
|
+
return nodes;
|
|
326
|
+
}
|
|
312
327
|
const result = [];
|
|
313
328
|
for (const node of nodes) {
|
|
314
329
|
// 递归检查子节点是否匹配
|
|
315
330
|
const matchedChildren = node[options.childField] && node[options.childField].length > 0
|
|
316
|
-
? fuzzySearchTree(node[options.childField] || [],
|
|
331
|
+
? fuzzySearchTree(node[options.childField] || [], filterCondition, options)
|
|
317
332
|
: [];
|
|
318
333
|
// 检查当前节点是否匹配或者有匹配的子节点
|
|
319
|
-
if (
|
|
334
|
+
if ((objectHas(filterCondition, 'filter')
|
|
335
|
+
? filterCondition.filter(node)
|
|
336
|
+
: !options.ignoreCase
|
|
337
|
+
? node[options.nameField].includes(filterCondition.keyword)
|
|
338
|
+
: node[options.nameField].toLowerCase().includes(filterCondition.keyword.toLowerCase())) ||
|
|
339
|
+
matchedChildren.length > 0) {
|
|
320
340
|
// 将当前节点加入结果中
|
|
321
341
|
if (node[options.childField]) {
|
|
322
342
|
if (matchedChildren.length > 0) {
|
|
@@ -325,7 +345,7 @@ function fuzzySearchTree(nodes, query, options = defaultSearchTreeOptions) {
|
|
|
325
345
|
[options.childField]: matchedChildren // 包含匹配的子节点
|
|
326
346
|
});
|
|
327
347
|
}
|
|
328
|
-
else if (options.
|
|
348
|
+
else if (options.removeEmptyChild) {
|
|
329
349
|
node[options.childField] && delete node[options.childField];
|
|
330
350
|
result.push({
|
|
331
351
|
...node
|
package/lib/es/type.js
CHANGED
package/lib/es/unique.js
CHANGED
package/lib/es/url.js
CHANGED
package/lib/es/validator.js
CHANGED
package/lib/es/variable.js
CHANGED
package/lib/es/watermark.js
CHANGED
package/lib/es/we-decode.js
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -380,7 +380,7 @@ declare function objectMap<O extends AnyObject, T>(obj: O, iterator: (val: O[key
|
|
|
380
380
|
*/
|
|
381
381
|
declare function objectPick<O extends AnyObject, K extends Extract<keyof O, string>[]>(obj: O, keys: K): Pick<O, ArrayElements<K>>;
|
|
382
382
|
/**
|
|
383
|
-
*
|
|
383
|
+
* 对象去除
|
|
384
384
|
* @param {O} obj
|
|
385
385
|
* @param {K} keys
|
|
386
386
|
* @returns {Pick<O, ArrayElements<K>>}
|
|
@@ -410,6 +410,10 @@ declare function objectGet(obj: AnyObject, path: string, strict?: boolean): {
|
|
|
410
410
|
};
|
|
411
411
|
/**
|
|
412
412
|
* 深拷贝堪称完全体 即:任何类型的数据都会被深拷贝
|
|
413
|
+
*
|
|
414
|
+
* 包含对null、原始值、对象循环引用的处理
|
|
415
|
+
*
|
|
416
|
+
* 对Map、Set、ArrayBuffer、Date、RegExp、Array、Object及原型链属性方法执行深拷贝
|
|
413
417
|
* @param {T} source
|
|
414
418
|
* @param {WeakMap} map
|
|
415
419
|
* @returns {T}
|
|
@@ -762,7 +766,12 @@ interface IFieldOptions {
|
|
|
762
766
|
interface ISearchTreeOpts {
|
|
763
767
|
childField: string;
|
|
764
768
|
nameField: string;
|
|
765
|
-
|
|
769
|
+
removeEmptyChild: boolean;
|
|
770
|
+
ignoreCase: boolean;
|
|
771
|
+
}
|
|
772
|
+
interface IFilterCondition<V> {
|
|
773
|
+
keyword?: string;
|
|
774
|
+
filter?: (args: V) => boolean;
|
|
766
775
|
}
|
|
767
776
|
/**
|
|
768
777
|
* 深度优先遍历函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
@@ -774,14 +783,18 @@ interface ISearchTreeOpts {
|
|
|
774
783
|
*/
|
|
775
784
|
declare function forEachDeep<V>(tree: ArrayLike<V>, iterator: (val: V, i: number, currentArr: ArrayLike<V>, tree: ArrayLike<V>, parent: V | null, level: number) => boolean | void, children?: string, isReverse?: boolean): void;
|
|
776
785
|
/**
|
|
777
|
-
* 深度优先遍历的Map函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
786
|
+
* 创建一个新数组, 深度优先遍历的Map函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
787
|
+
*
|
|
788
|
+
* 可遍历任何带有 length 属性和数字键的类数组对象
|
|
778
789
|
* @param {ArrayLike<V>} tree 树形数据
|
|
779
790
|
* @param {Function} iterator 迭代函数, 返回值为true时continue, 返回值为false时break
|
|
780
791
|
* @param {string} children 定制子元素的key
|
|
781
792
|
* @param {boolean} isReverse 是否反向遍历
|
|
782
793
|
* @returns {any[]} 新的一棵树
|
|
783
794
|
*/
|
|
784
|
-
declare function mapDeep<
|
|
795
|
+
declare function mapDeep<T>(tree: T[], iterator: (val: T, i: number, currentArr: T[], tree: T[], parent: T | null, level: number) => {
|
|
796
|
+
[k: string | number]: any;
|
|
797
|
+
} | boolean, children?: string, isReverse?: boolean): any[];
|
|
785
798
|
type IdLike = number | string;
|
|
786
799
|
interface ITreeConf {
|
|
787
800
|
id: string | number;
|
|
@@ -851,12 +864,19 @@ declare function formatTree(list: any[], options?: IFieldOptions): any[];
|
|
|
851
864
|
declare function flatTree(treeList: any[], options?: IFieldOptions): any[];
|
|
852
865
|
/**
|
|
853
866
|
* 模糊搜索函数,返回包含搜索字符的节点及其祖先节点, 适用于树型组件的字符过滤功能
|
|
854
|
-
*
|
|
855
|
-
*
|
|
867
|
+
* 以下搜索条件二选一,按先后优先级处理:
|
|
868
|
+
* 1. 过滤函数filter, 返回true/false
|
|
869
|
+
* 2. 匹配关键词,支持是否启用忽略大小写来判断
|
|
870
|
+
*
|
|
871
|
+
* 有以下特性:
|
|
872
|
+
* 1. 可配置removeEmptyChild字段,来决定是否移除搜索结果中的空children字段
|
|
873
|
+
* 2. 若无任何过滤条件或keyword模式匹配且keyword为空串,返回原对象;其他情况返回新数组
|
|
874
|
+
* @param {V[]} nodes
|
|
875
|
+
* @param {IFilterCondition} filterCondition
|
|
856
876
|
* @param {ISearchTreeOpts} options
|
|
857
|
-
* @returns {
|
|
877
|
+
* @returns {V[]}
|
|
858
878
|
*/
|
|
859
|
-
declare function fuzzySearchTree(nodes:
|
|
879
|
+
declare function fuzzySearchTree<V>(nodes: V[], filterCondition: IFilterCondition<V>, options?: ISearchTreeOpts): V[];
|
|
860
880
|
|
|
861
881
|
/**
|
|
862
882
|
* 数值安全乘法
|
|
@@ -1057,4 +1077,4 @@ declare function replaceVarFromString(sourceStr: string, targetObj: Record<strin
|
|
|
1057
1077
|
*/
|
|
1058
1078
|
declare function executeInScope(code: string, scope?: Record<string, any>): any;
|
|
1059
1079
|
|
|
1060
|
-
export { type AnyArray, type AnyFunc, type AnyObject, type ArrayElements, type DateObj, type DateValue, type DebounceFunc, EMAIL_REGEX, type FileType, HEX_POOL, HTTP_URL_REGEX, type ICanvasWM, type ICompressOptions, type IFieldOptions, IPV4_REGEX, IPV6_REGEX, type ISearchTreeOpts, type ITreeConf, type IdLike, type LooseParamValue, type LooseParams, type ObjectAssignItem, type OnceFunc, PHONE_REGEX, type Params, type PartialDeep, type RandomString, type ReadyCallback, type Replacer, STRING_ARABIC_NUMERALS, STRING_LOWERCASE_ALPHA, STRING_POOL, STRING_UPPERCASE_ALPHA, type SetStyle, type SmoothScrollOptions, type Style, type ThrottleFunc, UNIQUE_NUMBER_SAFE_LENGTH, URL_REGEX, type UniqueString, type Url, type WithChildren, add, addClass, arrayEach, arrayEachAsync, arrayInsertBefore, arrayLike, arrayRemove, asyncMap, buildTree, calculateDate, calculateDateTime, chooseLocalFile, cloneDeep, compressImg, cookieDel, cookieGet, cookieSet, copyText, crossOriginDownload, dateParse, dateToEnd, dateToStart, debounce, decodeFromBase64, divide, downloadBlob, downloadData, downloadHref, downloadURL, encodeToBase64, escapeRegExp, executeInScope, flatTree, forEachDeep, formatDate, formatNumber, formatTree, fuzzySearchTree, genCanvasWM, getComputedCssVal, getGlobal, getStrWidthPx, getStyle, hasClass, isArray, isBigInt, isBoolean, isDate, isDigit, isDomReady, isEmail, isEmpty, isError, isFloat, isFunction, isIdNo, isInteger, isIpV4, isIpV6, isJsonString, isNaN, isNull, isNullOrUnDef, isNumber, isNumerical, isObject, isPhone, isPlainObject, isPrimitive, isRegExp, isString, isSymbol, isUndefined, isUrl, isValidDate, mapDeep, multiply, numberAbbr, numberToHex, objectAssign, objectEach, objectEachAsync, objectFill, objectGet, objectHas, objectMap, objectAssign as objectMerge, objectOmit, objectPick, onDomReady, once, parseQueryParams, parseVarFromString, pathJoin, pathNormalize, qsParse, qsStringify, randomNumber, randomString, randomUuid, removeClass, replaceVarFromString, searchTreeById, setGlobal, setStyle, smoothScroll, stringAssign, stringCamelCase, stringEscapeHtml, stringFill, stringFormat, stringKebabCase, strip, subtract, supportCanvas, throttle, tooltipEvent, typeIs, uniqueNumber, uniqueString, uniqueSymbol, urlDelParams, urlParse, urlSetParams, urlStringify, wait, weAtob, weBtoa };
|
|
1080
|
+
export { type AnyArray, type AnyFunc, type AnyObject, type ArrayElements, type DateObj, type DateValue, type DebounceFunc, EMAIL_REGEX, type FileType, HEX_POOL, HTTP_URL_REGEX, type ICanvasWM, type ICompressOptions, type IFieldOptions, type IFilterCondition, IPV4_REGEX, IPV6_REGEX, type ISearchTreeOpts, type ITreeConf, type IdLike, type LooseParamValue, type LooseParams, type ObjectAssignItem, type OnceFunc, PHONE_REGEX, type Params, type PartialDeep, type RandomString, type ReadyCallback, type Replacer, STRING_ARABIC_NUMERALS, STRING_LOWERCASE_ALPHA, STRING_POOL, STRING_UPPERCASE_ALPHA, type SetStyle, type SmoothScrollOptions, type Style, type ThrottleFunc, UNIQUE_NUMBER_SAFE_LENGTH, URL_REGEX, type UniqueString, type Url, type WithChildren, add, addClass, arrayEach, arrayEachAsync, arrayInsertBefore, arrayLike, arrayRemove, asyncMap, buildTree, calculateDate, calculateDateTime, chooseLocalFile, cloneDeep, compressImg, cookieDel, cookieGet, cookieSet, copyText, crossOriginDownload, dateParse, dateToEnd, dateToStart, debounce, decodeFromBase64, divide, downloadBlob, downloadData, downloadHref, downloadURL, encodeToBase64, escapeRegExp, executeInScope, flatTree, forEachDeep, formatDate, formatNumber, formatTree, fuzzySearchTree, genCanvasWM, getComputedCssVal, getGlobal, getStrWidthPx, getStyle, hasClass, isArray, isBigInt, isBoolean, isDate, isDigit, isDomReady, isEmail, isEmpty, isError, isFloat, isFunction, isIdNo, isInteger, isIpV4, isIpV6, isJsonString, isNaN, isNull, isNullOrUnDef, isNumber, isNumerical, isObject, isPhone, isPlainObject, isPrimitive, isRegExp, isString, isSymbol, isUndefined, isUrl, isValidDate, mapDeep, multiply, numberAbbr, numberToHex, objectAssign, objectEach, objectEachAsync, objectFill, objectGet, objectHas, objectMap, objectAssign as objectMerge, objectOmit, objectPick, onDomReady, once, parseQueryParams, parseVarFromString, pathJoin, pathNormalize, qsParse, qsStringify, randomNumber, randomString, randomUuid, removeClass, replaceVarFromString, searchTreeById, setGlobal, setStyle, smoothScroll, stringAssign, stringCamelCase, stringEscapeHtml, stringFill, stringFormat, stringKebabCase, strip, subtract, supportCanvas, throttle, tooltipEvent, typeIs, uniqueNumber, uniqueString, uniqueSymbol, urlDelParams, urlParse, urlSetParams, urlStringify, wait, weAtob, weBtoa };
|
package/lib/umd/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* sculp-js v1.7.
|
|
2
|
+
* sculp-js v1.7.2
|
|
3
3
|
* (c) 2023-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -309,7 +309,7 @@
|
|
|
309
309
|
return obj2;
|
|
310
310
|
}
|
|
311
311
|
/**
|
|
312
|
-
*
|
|
312
|
+
* 对象去除
|
|
313
313
|
* @param {O} obj
|
|
314
314
|
* @param {K} keys
|
|
315
315
|
* @returns {Pick<O, ArrayElements<K>>}
|
|
@@ -424,12 +424,16 @@
|
|
|
424
424
|
}
|
|
425
425
|
/**
|
|
426
426
|
* 深拷贝堪称完全体 即:任何类型的数据都会被深拷贝
|
|
427
|
+
*
|
|
428
|
+
* 包含对null、原始值、对象循环引用的处理
|
|
429
|
+
*
|
|
430
|
+
* 对Map、Set、ArrayBuffer、Date、RegExp、Array、Object及原型链属性方法执行深拷贝
|
|
427
431
|
* @param {T} source
|
|
428
432
|
* @param {WeakMap} map
|
|
429
433
|
* @returns {T}
|
|
430
434
|
*/
|
|
431
435
|
function cloneDeep(source, map = new WeakMap()) {
|
|
432
|
-
//
|
|
436
|
+
// 处理原始类型和 null/undefined
|
|
433
437
|
if (source === null || typeof source !== 'object') {
|
|
434
438
|
return source;
|
|
435
439
|
}
|
|
@@ -437,28 +441,33 @@
|
|
|
437
441
|
if (map.has(source)) {
|
|
438
442
|
return map.get(source);
|
|
439
443
|
}
|
|
440
|
-
// 处理
|
|
444
|
+
// 处理 ArrayBuffer
|
|
445
|
+
if (source instanceof ArrayBuffer) {
|
|
446
|
+
const copy = new ArrayBuffer(source.byteLength);
|
|
447
|
+
new Uint8Array(copy).set(new Uint8Array(source));
|
|
448
|
+
map.set(source, copy);
|
|
449
|
+
return copy;
|
|
450
|
+
}
|
|
451
|
+
// 处理 DataView 和 TypedArray (Uint8Array 等)
|
|
452
|
+
if (ArrayBuffer.isView(source)) {
|
|
453
|
+
const constructor = source.constructor;
|
|
454
|
+
const bufferCopy = cloneDeep(source.buffer, map);
|
|
455
|
+
return new constructor(bufferCopy, source.byteOffset, source.length);
|
|
456
|
+
}
|
|
457
|
+
// 处理 Date 对象
|
|
441
458
|
if (source instanceof Date) {
|
|
442
459
|
const copy = new Date(source.getTime());
|
|
443
460
|
map.set(source, copy);
|
|
444
461
|
return copy;
|
|
445
462
|
}
|
|
446
|
-
// 处理 RegExp
|
|
463
|
+
// 处理 RegExp 对象
|
|
447
464
|
if (source instanceof RegExp) {
|
|
448
465
|
const copy = new RegExp(source.source, source.flags);
|
|
466
|
+
copy.lastIndex = source.lastIndex; // 保留匹配状态
|
|
449
467
|
map.set(source, copy);
|
|
450
468
|
return copy;
|
|
451
469
|
}
|
|
452
|
-
//
|
|
453
|
-
if (Array.isArray(source)) {
|
|
454
|
-
const copy = [];
|
|
455
|
-
map.set(source, copy);
|
|
456
|
-
for (const item of source) {
|
|
457
|
-
copy.push(cloneDeep(item, map));
|
|
458
|
-
}
|
|
459
|
-
return copy;
|
|
460
|
-
}
|
|
461
|
-
// 处理 Map 类型
|
|
470
|
+
// 处理 Map
|
|
462
471
|
if (source instanceof Map) {
|
|
463
472
|
const copy = new Map();
|
|
464
473
|
map.set(source, copy);
|
|
@@ -467,7 +476,7 @@
|
|
|
467
476
|
});
|
|
468
477
|
return copy;
|
|
469
478
|
}
|
|
470
|
-
// 处理 Set
|
|
479
|
+
// 处理 Set
|
|
471
480
|
if (source instanceof Set) {
|
|
472
481
|
const copy = new Set();
|
|
473
482
|
map.set(source, copy);
|
|
@@ -476,19 +485,47 @@
|
|
|
476
485
|
});
|
|
477
486
|
return copy;
|
|
478
487
|
}
|
|
479
|
-
//
|
|
480
|
-
if (source
|
|
481
|
-
const copy =
|
|
482
|
-
new Uint8Array(copy).set(new Uint8Array(source));
|
|
488
|
+
// 处理数组 (包含稀疏数组)
|
|
489
|
+
if (Array.isArray(source)) {
|
|
490
|
+
const copy = Array.from({ length: source.length });
|
|
483
491
|
map.set(source, copy);
|
|
492
|
+
// 克隆所有有效索引
|
|
493
|
+
for (let i = 0; i < source.length; i++) {
|
|
494
|
+
if (i in source) {
|
|
495
|
+
// 保留空位
|
|
496
|
+
copy[i] = cloneDeep(source[i], map);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
// 克隆数组的自定义属性
|
|
500
|
+
const descriptors = Object.getOwnPropertyDescriptors(source);
|
|
501
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
502
|
+
Object.defineProperty(copy, key, {
|
|
503
|
+
...descriptors[key],
|
|
504
|
+
value: cloneDeep(descriptors[key].value, map)
|
|
505
|
+
});
|
|
506
|
+
}
|
|
484
507
|
return copy;
|
|
485
508
|
}
|
|
486
|
-
//
|
|
509
|
+
// 处理普通对象和类实例
|
|
487
510
|
const copy = Object.create(Object.getPrototypeOf(source));
|
|
488
511
|
map.set(source, copy);
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
512
|
+
const descriptors = Object.getOwnPropertyDescriptors(source);
|
|
513
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
514
|
+
const descriptor = descriptors[key];
|
|
515
|
+
if ('value' in descriptor) {
|
|
516
|
+
// 克隆数据属性
|
|
517
|
+
descriptor.value = cloneDeep(descriptor.value, map);
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
// 处理访问器属性 (getter/setter)
|
|
521
|
+
if (descriptor.get) {
|
|
522
|
+
descriptor.get = cloneDeep(descriptor.get, map);
|
|
523
|
+
}
|
|
524
|
+
if (descriptor.set) {
|
|
525
|
+
descriptor.set = cloneDeep(descriptor.set, map);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
Object.defineProperty(copy, key, descriptor);
|
|
492
529
|
}
|
|
493
530
|
return copy;
|
|
494
531
|
}
|
|
@@ -2179,7 +2216,8 @@
|
|
|
2179
2216
|
const defaultSearchTreeOptions = {
|
|
2180
2217
|
childField: 'children',
|
|
2181
2218
|
nameField: 'name',
|
|
2182
|
-
|
|
2219
|
+
removeEmptyChild: false,
|
|
2220
|
+
ignoreCase: true
|
|
2183
2221
|
};
|
|
2184
2222
|
/**
|
|
2185
2223
|
* 深度优先遍历函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
@@ -2236,7 +2274,9 @@
|
|
|
2236
2274
|
walk(tree, null);
|
|
2237
2275
|
}
|
|
2238
2276
|
/**
|
|
2239
|
-
* 深度优先遍历的Map函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
2277
|
+
* 创建一个新数组, 深度优先遍历的Map函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
|
|
2278
|
+
*
|
|
2279
|
+
* 可遍历任何带有 length 属性和数字键的类数组对象
|
|
2240
2280
|
* @param {ArrayLike<V>} tree 树形数据
|
|
2241
2281
|
* @param {Function} iterator 迭代函数, 返回值为true时continue, 返回值为false时break
|
|
2242
2282
|
* @param {string} children 定制子元素的key
|
|
@@ -2472,20 +2512,36 @@
|
|
|
2472
2512
|
}
|
|
2473
2513
|
/**
|
|
2474
2514
|
* 模糊搜索函数,返回包含搜索字符的节点及其祖先节点, 适用于树型组件的字符过滤功能
|
|
2475
|
-
*
|
|
2476
|
-
*
|
|
2515
|
+
* 以下搜索条件二选一,按先后优先级处理:
|
|
2516
|
+
* 1. 过滤函数filter, 返回true/false
|
|
2517
|
+
* 2. 匹配关键词,支持是否启用忽略大小写来判断
|
|
2518
|
+
*
|
|
2519
|
+
* 有以下特性:
|
|
2520
|
+
* 1. 可配置removeEmptyChild字段,来决定是否移除搜索结果中的空children字段
|
|
2521
|
+
* 2. 若无任何过滤条件或keyword模式匹配且keyword为空串,返回原对象;其他情况返回新数组
|
|
2522
|
+
* @param {V[]} nodes
|
|
2523
|
+
* @param {IFilterCondition} filterCondition
|
|
2477
2524
|
* @param {ISearchTreeOpts} options
|
|
2478
|
-
* @returns {
|
|
2525
|
+
* @returns {V[]}
|
|
2479
2526
|
*/
|
|
2480
|
-
function fuzzySearchTree(nodes,
|
|
2527
|
+
function fuzzySearchTree(nodes, filterCondition, options = defaultSearchTreeOptions) {
|
|
2528
|
+
if (!objectHas(filterCondition, 'filter') &&
|
|
2529
|
+
(!objectHas(filterCondition, 'keyword') || isEmpty(filterCondition.keyword))) {
|
|
2530
|
+
return nodes;
|
|
2531
|
+
}
|
|
2481
2532
|
const result = [];
|
|
2482
2533
|
for (const node of nodes) {
|
|
2483
2534
|
// 递归检查子节点是否匹配
|
|
2484
2535
|
const matchedChildren = node[options.childField] && node[options.childField].length > 0
|
|
2485
|
-
? fuzzySearchTree(node[options.childField] || [],
|
|
2536
|
+
? fuzzySearchTree(node[options.childField] || [], filterCondition, options)
|
|
2486
2537
|
: [];
|
|
2487
2538
|
// 检查当前节点是否匹配或者有匹配的子节点
|
|
2488
|
-
if (
|
|
2539
|
+
if ((objectHas(filterCondition, 'filter')
|
|
2540
|
+
? filterCondition.filter(node)
|
|
2541
|
+
: !options.ignoreCase
|
|
2542
|
+
? node[options.nameField].includes(filterCondition.keyword)
|
|
2543
|
+
: node[options.nameField].toLowerCase().includes(filterCondition.keyword.toLowerCase())) ||
|
|
2544
|
+
matchedChildren.length > 0) {
|
|
2489
2545
|
// 将当前节点加入结果中
|
|
2490
2546
|
if (node[options.childField]) {
|
|
2491
2547
|
if (matchedChildren.length > 0) {
|
|
@@ -2494,7 +2550,7 @@
|
|
|
2494
2550
|
[options.childField]: matchedChildren // 包含匹配的子节点
|
|
2495
2551
|
});
|
|
2496
2552
|
}
|
|
2497
|
-
else if (options.
|
|
2553
|
+
else if (options.removeEmptyChild) {
|
|
2498
2554
|
node[options.childField] && delete node[options.childField];
|
|
2499
2555
|
result.push({
|
|
2500
2556
|
...node
|