ph-utils 0.9.15 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
- ## ph-utils
2
-
3
- 整理了 js 前后端开发(web + nodejs)时常用的一些工具;[详细文档](https://gitee.com/towardly/ph/wikis/Home?sort_id=4035190)
4
-
5
- ### 包含如下工具文件
6
-
7
- `index` 基础工具类、`date` 跟日期相关的工具类、`file` 文件操作相关工具类[**服务端**]、`server` 服务端工具类、`validator` 数据验证、`dom` 浏览器节点操作相关[**前端**]、`web` 一些只适用于前端相关的工具、`color` 颜色相关工具
1
+ ## ph-utils
2
+
3
+ 整理了 js 前后端开发(web + nodejs)时常用的一些工具;[详细文档](https://gitee.com/towardly/ph/wikis/Home?sort_id=4035190)
4
+
5
+ ### 包含如下工具文件
6
+
7
+ `index` 基础工具类、`date` 跟日期相关的工具类、`file` 文件操作相关工具类[**服务端**]、`server` 服务端工具类、`validator` 数据验证、`dom` 浏览器节点操作相关[**前端**]、`web` 一些只适用于前端相关的工具、`color` 颜色相关工具
package/lib/dom.d.ts CHANGED
@@ -3,6 +3,20 @@
3
3
  * @param {string} selector 选择器
4
4
  */
5
5
  export declare function elem(selector: string | HTMLElement, dom?: HTMLElement): NodeListOf<HTMLElement> | HTMLElement[];
6
+ /**
7
+ * 根据选择器获取 DOM 元素。
8
+ * @param selector - 选择器字符串或 HTMLElement 实例。
9
+ * @param dom - 可选参数,指定在哪个 DOM 节点下查找元素,默认为 document。
10
+ * @returns 返回匹配到的 HTMLElement 实例。
11
+ */
12
+ export declare function $(selector: string | HTMLElement, dom?: HTMLElement): NodeListOf<HTMLElement> | HTMLElement[];
13
+ /**
14
+ * 根据选择器获取匹配的第一个 DOM 元素。
15
+ * @param selector - 选择器字符串或直接的 HTMLElement。
16
+ * @param dom - 可选的父级 DOM 元素,默认为当前文档。
17
+ * @returns 返回匹配的第一个 HTMLElement,如果没有找到则返回 undefined。
18
+ */
19
+ export declare function $one(selector: string | HTMLElement, dom?: HTMLElement): HTMLElement;
6
20
  /**
7
21
  * 为节点添加 class
8
22
  * @param {HTMLElement} elem 待添加 class 的节点
@@ -46,6 +60,13 @@ export declare function on<T extends Event>(element: HTMLElement, listener: stri
46
60
  eventFlag?: string;
47
61
  eventStop?: boolean;
48
62
  }): void;
63
+ /**
64
+ * 移除指定元素的事件监听器。
65
+ * @param el - 要移除监听器的 HTML 元素。
66
+ * @param listener - 事件名称。
67
+ * @param fn - 要移除的事件监听器函数。
68
+ */
69
+ export declare function off(el: HTMLElement, listener: string, fn: EventListener): void;
49
70
  /**
50
71
  * 设置或获取节点的 innerHTML 属性
51
72
  * @param element
@@ -74,6 +95,20 @@ export declare function iterate(elems: NodeList | HTMLElement[], fn: (el: HTMLEl
74
95
  * @returns
75
96
  */
76
97
  export declare function attr(elem: HTMLElement, key: string, value?: string): string | null | undefined;
98
+ /**
99
+ * 获取属性值
100
+ * @param key 属性名称
101
+ */
102
+ export declare function getAttr(el: HTMLElement, key: string): string;
103
+ /**
104
+ * 获取属性值,同时将值转换为默认值的类型,如果未赋值,则返回默认值;
105
+ * @param key 属性名称
106
+ * @param defaultValue 默认值
107
+ */
108
+ export declare function getAttr(el: HTMLElement, filepath: string, defaultValue: string): string;
109
+ export declare function getAttr(el: HTMLElement, filepath: string, defaultValue: number): number;
110
+ export declare function getAttr(el: HTMLElement, filepath: string, defaultValue: boolean): boolean;
111
+ export declare function getAttr<T extends Record<string, string | number | boolean>>(el: HTMLElement, filepath: string, defaultValue: T): T;
77
112
  /**
78
113
  * 获取指定节点的父节点
79
114
  * @param el
@@ -108,3 +143,45 @@ export declare function isVisible(el: HTMLElement, parent?: HTMLElement | null |
108
143
  * @returns {boolean} 如果设备是移动设备,则返回true;否则返回false。
109
144
  */
110
145
  export declare function isMobile(): boolean;
146
+ /**
147
+ * 格式化类名,支持数组和对象两种形式。
148
+ * - 数组形式:数组中的每个元素代表一个类名,非空元素将被添加到结果字符串中。
149
+ * - 对象形式:对象的键代表类名,值为真(非空、非undefined、非null)时,键将被添加到结果字符串中。
150
+ * @param classObj - 类名对象或数组
151
+ * @returns 格式化后的类名字符串
152
+ */
153
+ export declare function formatClass(classObj: (boolean | string | undefined | null)[] | Record<string, boolean | string | undefined | null>): string;
154
+ /**
155
+ * 在下一个动画帧执行回调函数。
156
+ * @param cb - 要在下一个动画帧执行的回调函数。
157
+ */
158
+ export declare function nextTick(cb: () => void): void;
159
+ /**
160
+ * 对指定的 HTML 元素应用显示过渡效果。
161
+ * @param target - 要应用过渡效果的 HTML 元素。
162
+ * @param properties - 包含要改变的 CSS 属性及其目标值的数组。eg. [['opacity', '0.5']]
163
+ * @param duration - 过渡效果的持续时间,默认为 "0.3s"。
164
+ * 该方法首先将元素的 display 属性设置为 "none",然后设置过渡属性,
165
+ * 在下一个 DOM 更新周期后显示元素并移除设置的属性,从而实现过渡效果。
166
+ *
167
+ * ```
168
+ * startTransition($msg, [
169
+ ["opacity", "0"],
170
+ ["transform", "translate3d(-50%, -100%, 0)"],
171
+ ]);
172
+ * ```
173
+ */
174
+ export declare function startTransition(target: HTMLElement, properties: [string, string][], duration?: string): void;
175
+ /**
176
+ * 结束元素的过渡效果,并在过渡结束后隐藏元素。
177
+ * @param target - 要操作的 HTML 元素。
178
+ * @param properties - 包含要设置的 CSS 属性和值的数组。
179
+ * @param finish - 过渡结束后可选的回调函数。
180
+ */
181
+ export declare function endTransition(target: HTMLElement, properties: [string, string][], finish?: () => void): void;
182
+ /**
183
+ * 隐藏 Transition 组件
184
+ * @param el Transition 组件或者选择器, 不传则为: l-transition
185
+ * @param remove 是否在隐藏后移除元素, 对应 vue-vIf
186
+ */
187
+ export declare function hideTransition(el?: string | HTMLElement, remove?: boolean): void;
package/lib/dom.js CHANGED
@@ -16,6 +16,24 @@ export function elem(selector, dom) {
16
16
  return [selector];
17
17
  }
18
18
  }
19
+ /**
20
+ * 根据选择器获取 DOM 元素。
21
+ * @param selector - 选择器字符串或 HTMLElement 实例。
22
+ * @param dom - 可选参数,指定在哪个 DOM 节点下查找元素,默认为 document。
23
+ * @returns 返回匹配到的 HTMLElement 实例。
24
+ */
25
+ export function $(selector, dom) {
26
+ return elem(selector, dom);
27
+ }
28
+ /**
29
+ * 根据选择器获取匹配的第一个 DOM 元素。
30
+ * @param selector - 选择器字符串或直接的 HTMLElement。
31
+ * @param dom - 可选的父级 DOM 元素,默认为当前文档。
32
+ * @returns 返回匹配的第一个 HTMLElement,如果没有找到则返回 undefined。
33
+ */
34
+ export function $one(selector, dom) {
35
+ return elem(selector, dom)[0];
36
+ }
19
37
  /**
20
38
  * 为节点添加 class
21
39
  * @param {HTMLElement} elem 待添加 class 的节点
@@ -98,6 +116,15 @@ export function on(element, listener, fn, once = false) {
98
116
  element.addEventListener(listener, fn, eventExtra);
99
117
  }
100
118
  }
119
+ /**
120
+ * 移除指定元素的事件监听器。
121
+ * @param el - 要移除监听器的 HTML 元素。
122
+ * @param listener - 事件名称。
123
+ * @param fn - 要移除的事件监听器函数。
124
+ */
125
+ export function off(el, listener, fn) {
126
+ el.removeEventListener(listener, fn);
127
+ }
101
128
  /**
102
129
  * 设置或获取节点的 innerHTML 属性
103
130
  * @param element
@@ -156,6 +183,32 @@ export function attr(elem, key, value) {
156
183
  return elem.getAttribute("data-" + key);
157
184
  }
158
185
  }
186
+ export function getAttr(el, key, defaultValue) {
187
+ const value = el.getAttribute(key);
188
+ if (defaultValue == null)
189
+ return value;
190
+ const valueType = typeof defaultValue;
191
+ if (value == null)
192
+ return defaultValue;
193
+ // 类型转换
194
+ if (valueType === "bigint" || valueType === "number") {
195
+ if (value === "")
196
+ return defaultValue;
197
+ return Number(value);
198
+ }
199
+ if (valueType === "boolean") {
200
+ if (value === "" || value === "1" || value === "true" || value === key) {
201
+ return true;
202
+ }
203
+ return false;
204
+ }
205
+ if (valueType === "object") {
206
+ if (value === "")
207
+ return defaultValue;
208
+ return JSON.parse(value);
209
+ }
210
+ return value;
211
+ }
159
212
  /**
160
213
  * 获取指定节点的父节点
161
214
  * @param el
@@ -237,3 +290,114 @@ export function isMobile() {
237
290
  // 如果是移动设备或屏幕尺寸符合移动设备特征,则返回true
238
291
  return isMobile || isScreenMobile;
239
292
  }
293
+ /**
294
+ * 格式化类名,支持数组和对象两种形式。
295
+ * - 数组形式:数组中的每个元素代表一个类名,非空元素将被添加到结果字符串中。
296
+ * - 对象形式:对象的键代表类名,值为真(非空、非undefined、非null)时,键将被添加到结果字符串中。
297
+ * @param classObj - 类名对象或数组
298
+ * @returns 格式化后的类名字符串
299
+ */
300
+ export function formatClass(classObj) {
301
+ let classes = "";
302
+ if (Array.isArray(classObj)) {
303
+ for (let i = 0, len = classObj.length; i < len; i++) {
304
+ const item = classObj[i];
305
+ if (item) {
306
+ classes += `${item} `;
307
+ }
308
+ }
309
+ }
310
+ else {
311
+ for (const key in classObj) {
312
+ if (classObj[key]) {
313
+ classes += `${key} `;
314
+ }
315
+ }
316
+ }
317
+ return classes.trim();
318
+ }
319
+ /**
320
+ * 在下一个动画帧执行回调函数。
321
+ * @param cb - 要在下一个动画帧执行的回调函数。
322
+ */
323
+ export function nextTick(cb) {
324
+ requestAnimationFrame(() => {
325
+ cb();
326
+ });
327
+ }
328
+ /**
329
+ * 对指定的 HTML 元素应用显示过渡效果。
330
+ * @param target - 要应用过渡效果的 HTML 元素。
331
+ * @param properties - 包含要改变的 CSS 属性及其目标值的数组。eg. [['opacity', '0.5']]
332
+ * @param duration - 过渡效果的持续时间,默认为 "0.3s"。
333
+ * 该方法首先将元素的 display 属性设置为 "none",然后设置过渡属性,
334
+ * 在下一个 DOM 更新周期后显示元素并移除设置的属性,从而实现过渡效果。
335
+ *
336
+ * ```
337
+ * startTransition($msg, [
338
+ ["opacity", "0"],
339
+ ["transform", "translate3d(-50%, -100%, 0)"],
340
+ ]);
341
+ * ```
342
+ */
343
+ export function startTransition(target, properties, duration) {
344
+ target.style.setProperty("display", "none");
345
+ const trans = [];
346
+ for (let i = 0, len = properties.length; i < len; i++) {
347
+ const rec = properties[i];
348
+ target.style.setProperty(rec[0], rec[1]);
349
+ trans.push(`${rec[0]} ${duration}`);
350
+ }
351
+ if (duration) {
352
+ target.style.setProperty("transition", trans.join(", "));
353
+ }
354
+ nextTick(() => {
355
+ target.style.removeProperty("display");
356
+ nextTick(() => {
357
+ for (let i = 0, len = properties.length; i < len; i++) {
358
+ const rec = properties[i];
359
+ target.style.removeProperty(rec[0]);
360
+ }
361
+ });
362
+ });
363
+ }
364
+ /**
365
+ * 结束元素的过渡效果,并在过渡结束后隐藏元素。
366
+ * @param target - 要操作的 HTML 元素。
367
+ * @param properties - 包含要设置的 CSS 属性和值的数组。
368
+ * @param finish - 过渡结束后可选的回调函数。
369
+ */
370
+ export function endTransition(target, properties, finish) {
371
+ for (let i = 0, len = properties.length; i < len; i++) {
372
+ const rec = properties[i];
373
+ target.style.setProperty(rec[0], rec[1]);
374
+ }
375
+ target.addEventListener("transitionend", () => {
376
+ target.style.display = "none";
377
+ for (let i = 0, len = properties.length; i < len; i++) {
378
+ const rec = properties[i];
379
+ target.style.removeProperty(rec[0]);
380
+ }
381
+ if (finish != null) {
382
+ finish();
383
+ }
384
+ }, { once: true });
385
+ }
386
+ /**
387
+ * 隐藏 Transition 组件
388
+ * @param el Transition 组件或者选择器, 不传则为: l-transition
389
+ * @param remove 是否在隐藏后移除元素, 对应 vue-vIf
390
+ */
391
+ export function hideTransition(el, remove = false) {
392
+ el = el || "l-transition";
393
+ let $el = el;
394
+ if (typeof el === "string") {
395
+ $el = document.querySelector(el);
396
+ }
397
+ if ($el) {
398
+ $el.hide(() => {
399
+ if (remove)
400
+ $el.remove();
401
+ });
402
+ }
403
+ }
package/lib/theme.js CHANGED
@@ -19,10 +19,10 @@ export async function initTheme() {
19
19
  if ($themeStyle == null) {
20
20
  $themeStyle = document.createElement("style");
21
21
  $themeStyle.id = "theme-style";
22
- $themeStyle.innerHTML = `
23
- :root{color-scheme:light dark;}
24
- html.light{color-scheme: light;}
25
- html.dark {color-scheme: dark;}
22
+ $themeStyle.innerHTML = `
23
+ :root{color-scheme:light dark;}
24
+ html.light{color-scheme: light;}
25
+ html.dark {color-scheme: dark;}
26
26
  `;
27
27
  document.head.appendChild($themeStyle);
28
28
  }
package/package.json CHANGED
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "./*": "./lib/*"
70
70
  },
71
- "version": "0.9.15",
71
+ "version": "0.10.0",
72
72
  "type": "module",
73
73
  "repository": {
74
74
  "type": "git",
@@ -1,11 +0,0 @@
1
- /**
2
- * 复制数据, 可以从多种类型的数据
3
- * 1. 直接复制文本: await copy("待复制的文本")
4
- * 2. 复制节点上的 data-copy-text:
5
- * <button data-copy-text="这是待复制的文本">复制</button>
6
- * await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
7
- * 3. 直接复制节点本身数据: await copy('#a')
8
- * @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
9
- * @returns {Promise<boolean>} 是否复制成功
10
- */
11
- export declare function copy(source: string | HTMLElement): Promise<boolean>;
package/lib/clipboard.js DELETED
@@ -1,101 +0,0 @@
1
- /**
2
- * 创建一个临时节点缓存待复制数据
3
- * @param {String} value - 待复制文本
4
- * @return {HTMLElement}
5
- */
6
- function createFakeElement(value) {
7
- const fakeElement = document.createElement("textarea");
8
- fakeElement.style.border = "0";
9
- fakeElement.style.padding = "0";
10
- fakeElement.style.margin = "0";
11
- fakeElement.style.position = "absolute";
12
- fakeElement.style.left = "-9999px";
13
- fakeElement.style.top = "-9999";
14
- fakeElement.setAttribute("readonly", "");
15
- fakeElement.value = value;
16
- return fakeElement;
17
- }
18
- /** 通过执行 execCommand 来执行复制 */
19
- function copyFromCommand(text) {
20
- // 添加节点
21
- const fakeEl = createFakeElement(text);
22
- document.body.append(fakeEl);
23
- fakeEl.focus();
24
- fakeEl.select();
25
- // 执行复制
26
- const res = document.execCommand("copy");
27
- fakeEl.remove(); // 删除节点
28
- return Promise.resolve(res);
29
- }
30
- /** 使用 navigator.clipboard 复制 */
31
- function copyFromClipboard(text) {
32
- const theClipboard = navigator.clipboard;
33
- if (theClipboard != null) {
34
- return theClipboard
35
- .writeText(text)
36
- .then(() => {
37
- Promise.resolve(true);
38
- })
39
- .catch(() => Promise.resolve(false));
40
- }
41
- return Promise.resolve(false);
42
- }
43
- /** 解析待复制的文本 */
44
- function parseCopyText(source) {
45
- let copyText = null; // 待复制文本
46
- let sourceEl = null;
47
- // 获取待复制数据
48
- if (typeof source === "string") {
49
- // 从节点拿数据
50
- if (source.startsWith("#") || source.startsWith(".")) {
51
- sourceEl = document.querySelector(source);
52
- if (sourceEl == null) {
53
- copyText = source;
54
- }
55
- }
56
- else {
57
- copyText = source;
58
- }
59
- }
60
- if (source instanceof HTMLElement) {
61
- sourceEl = source;
62
- }
63
- // 从节点获取待复制数据
64
- if (sourceEl != null) {
65
- if (sourceEl.hasAttribute("data-copy-text")) {
66
- copyText = sourceEl.getAttribute("data-copy-text");
67
- }
68
- else {
69
- const tagName = sourceEl.tagName;
70
- if (tagName === "INPUT" || tagName === "TEXTAREA") {
71
- copyText = sourceEl.value;
72
- }
73
- else {
74
- copyText = sourceEl.textContent;
75
- }
76
- }
77
- }
78
- return copyText;
79
- }
80
- /**
81
- * 复制数据, 可以从多种类型的数据
82
- * 1. 直接复制文本: await copy("待复制的文本")
83
- * 2. 复制节点上的 data-copy-text:
84
- * <button data-copy-text="这是待复制的文本">复制</button>
85
- * await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
86
- * 3. 直接复制节点本身数据: await copy('#a')
87
- * @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
88
- * @returns {Promise<boolean>} 是否复制成功
89
- */
90
- export async function copy(source) {
91
- // 待复制文本
92
- const copyText = parseCopyText(source);
93
- if (copyText == null) {
94
- return Promise.resolve(false);
95
- }
96
- const v = await copyFromClipboard(copyText);
97
- if (v === false) {
98
- return copyFromCommand(copyText);
99
- }
100
- return Promise.resolve(true);
101
- }