ph-utils 0.9.14 → 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/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
- }