ph-utils 0.9.14 → 0.10.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/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/server.d.ts CHANGED
@@ -5,9 +5,18 @@ import type { SpawnOptions } from "node:child_process";
5
5
  * @param command 待执行的命令
6
6
  * @param args 命令参数
7
7
  */
8
- export declare function exec(command: string, args?: string[]): Promise<string>;
9
- export declare function exec(command: string, options?: SpawnOptions): Promise<string>;
10
- export declare function exec(command: string, args?: string[], options?: SpawnOptions): Promise<string>;
8
+ export declare function exec(command: string, args?: string[]): Promise<{
9
+ stdout: string;
10
+ stderr: string;
11
+ }>;
12
+ export declare function exec(command: string, options?: SpawnOptions): Promise<{
13
+ stdout: string;
14
+ stderr: string;
15
+ }>;
16
+ export declare function exec(command: string, args?: string[], options?: SpawnOptions): Promise<{
17
+ stdout: string;
18
+ stderr: string;
19
+ }>;
11
20
  /**
12
21
  * 解析环境变量;
13
22
  * 同时读取多个环境变量文件: .env, .env.local, .env.[development|test|production];
package/lib/server.js CHANGED
@@ -1,48 +1,32 @@
1
1
  import { execFile } from "node:child_process";
2
- import { parseEnv, parseArgs } from "node:util";
2
+ import { parseEnv, parseArgs, promisify } from "node:util";
3
3
  import { readFileSync } from "node:fs";
4
+ const execFilePromise = promisify(execFile);
4
5
  /**
5
6
  * 执行命令
6
7
  * @param cmd 执行的命令
7
8
  * @returns
8
9
  */
9
10
  export function exec(command, ...params) {
10
- let argvs = [];
11
- const commandItems = command.split(" ");
12
- const cmd = commandItems.shift();
13
- if (commandItems.length > 0) {
14
- argvs = commandItems;
15
- }
16
- let opts = {};
17
- if (params[0] != null) {
18
- if (params[0] instanceof Array) {
19
- argvs.push(...params[0]);
20
- if (params[1] != null) {
21
- opts = params[1];
22
- }
23
- } else {
24
- opts = params[0];
11
+ let argvs = [];
12
+ const commandItems = command.split(" ");
13
+ const cmd = commandItems.shift();
14
+ if (commandItems.length > 0) {
15
+ argvs = commandItems;
25
16
  }
26
- }
27
- return new Promise((resolve, reject) => {
28
- execFile(cmd, argvs, opts || {}, (err, stdout, stderr) => {
29
- if (err) {
30
- reject(err);
31
- } else {
32
- let msg = stdout || stderr;
33
- if (
34
- stderr != null &&
35
- (stderr.includes("error") || stderr.includes("Error"))
36
- ) {
37
- const error = new Error(stderr);
38
- error.type = "StdErr";
39
- reject(error);
40
- } else {
41
- resolve(msg);
17
+ let opts = { shell: true };
18
+ if (params[0] != null) {
19
+ if (params[0] instanceof Array) {
20
+ argvs.push(...params[0]);
21
+ if (params[1] != null) {
22
+ opts = params[1];
23
+ }
42
24
  }
43
- }
44
- });
45
- });
25
+ else {
26
+ opts = params[0];
27
+ }
28
+ }
29
+ return execFilePromise(cmd, argvs, opts);
46
30
  }
47
31
  /**
48
32
  * 解析环境变量;
@@ -64,37 +48,39 @@ export function exec(command, ...params) {
64
48
  * @returns
65
49
  */
66
50
  export function parseEnvs() {
67
- // development, test, production
68
- const files = [".env", ".env.local"];
69
- let nodeEnv = process.env.NODE_ENV;
70
- const { values } = parseArgs({
71
- options: {
72
- NODE_ENV: {
73
- type: "string",
74
- short: "n",
75
- },
76
- },
77
- strict: false,
78
- });
79
- if (values.NODE_ENV != null && typeof values.NODE_ENV === "string") {
80
- nodeEnv = values.NODE_ENV;
81
- }
82
- if (nodeEnv == null) {
83
- nodeEnv = "production";
84
- }
85
- process.env.NODE_ENV = nodeEnv;
86
- files.push(`.env.${nodeEnv}`);
87
- let envParsed = {};
88
- for (let i = 0, len = files.length; i < len; i++) {
89
- const file = files[i];
90
- try {
91
- const envContent = readFileSync(file, { encoding: "utf-8" });
92
- const envValue = parseEnv(envContent);
93
- envParsed = { ...envParsed, ...envValue };
94
- } catch (err) {}
95
- }
96
- for (const key in envParsed) {
97
- process.env[key] = envParsed[key];
98
- }
99
- return envParsed;
51
+ // development, test, production
52
+ const files = [".env", ".env.local"];
53
+ let nodeEnv = process.env.NODE_ENV;
54
+ const { values } = parseArgs({
55
+ options: {
56
+ NODE_ENV: {
57
+ type: "string",
58
+ short: "n",
59
+ },
60
+ },
61
+ strict: false,
62
+ });
63
+ if (values.NODE_ENV != null && typeof values.NODE_ENV === "string") {
64
+ nodeEnv = values.NODE_ENV;
65
+ }
66
+ if (nodeEnv == null) {
67
+ nodeEnv = "production";
68
+ }
69
+ process.env.NODE_ENV = nodeEnv;
70
+ files.push(`.env.${nodeEnv}`);
71
+ let envParsed = {};
72
+ for (let i = 0, len = files.length; i < len; i++) {
73
+ const file = files[i];
74
+ try {
75
+ const envContent = readFileSync(file, { encoding: "utf-8" });
76
+ const envValue = parseEnv(envContent);
77
+ envParsed = { ...envParsed, ...envValue };
78
+ // eslint-disable-next-line
79
+ }
80
+ catch (err) { }
81
+ }
82
+ for (const key in envParsed) {
83
+ process.env[key] = envParsed[key];
84
+ }
85
+ return envParsed;
100
86
  }
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.14",
71
+ "version": "0.10.0",
72
72
  "type": "module",
73
73
  "repository": {
74
74
  "type": "git",
@@ -82,7 +82,7 @@
82
82
  },
83
83
  "homepage": "https://gitee.com/towardly/ph/tree/master/packages/utils",
84
84
  "devDependencies": {
85
- "@types/node": "^22.7.9",
85
+ "@types/node": "^22.8.2",
86
86
  "typescript": "^5.6.3"
87
87
  },
88
88
  "files": [
@@ -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
- }