@cloudcome/utils-browser 0.0.0 → 1.1.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ ## [1.1.1](https://github.com/cloudcome/utils/compare/@cloudcome/utils-browser@1.1.0...@cloudcome/utils-browser@1.1.1) (2025-08-30)
7
+
8
+ **Note:** Version bump only for package @cloudcome/utils-browser
9
+
10
+ # 1.1.0 (2025-08-27)
11
+
12
+ ### Bug Fixes
13
+
14
+ * **utils-browser:** 修复 ios 拍照产生图片的尺寸问题 ([1e9b47d](https://github.com/cloudcome/utils/commit/1e9b47df68018cef80c050be48cdba206ec5e177))
15
+ * **utils-browser:** 修复图片加载逻辑 ([16e5a41](https://github.com/cloudcome/utils/commit/16e5a4152f29619d8abf767e7f97889216ebe1ae))
16
+ * **utils-browser:** 修正 cookie 过期时间格式 ([160c1c1](https://github.com/cloudcome/utils/commit/160c1c1107428f4c160b2e116454085a7fb3b83a))
17
+
18
+ ### Features
19
+
20
+ * **utils-browser:** 优化 canvas 工具函数并添加新功能 ([fb89067](https://github.com/cloudcome/utils/commit/fb890674a0a97c0f09df480592236273ff3b5172))
21
+ * **utils-browser:** 新增多个实用工具模块 ([6958f7a](https://github.com/cloudcome/utils/commit/6958f7a13e416b3330464ef9493957db605c4eb1))
22
+ * **utils-browser:** 添加 canvas 相关工具函数 ([536f9d7](https://github.com/cloudcome/utils/commit/536f9d72b071402af3c1d38952d5a0ffdb1906a2))
23
+ * **utils-browser:** 添加 Cookie 操作工具函数 ([cc7c014](https://github.com/cloudcome/utils/commit/cc7c01493141ecd4ef270192e87e51eac8ca2008))
24
+ * **utils-browser:** 添加下载功能 ([7fd2441](https://github.com/cloudcome/utils/commit/7fd24411e357aa6cbfb9e0ca9961d4fcc3cde6e7))
25
+ * **utils-browser:** 添加图片加载函数 ([f51210f](https://github.com/cloudcome/utils/commit/f51210f0af9c47a3033af19ce901a1b70f3882fc))
26
+ * **utils-browser:** 添加视频加载功能 ([d4ef7a5](https://github.com/cloudcome/utils/commit/d4ef7a59a379156dbba8737d18582288ae306900))
27
+ * **utils-browser:** 添加设置和获取元素样式功能 ([71e0b56](https://github.com/cloudcome/utils/commit/71e0b564b09b38020fd6aa9c85bc6b3e2e137d72))
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ☁️淡然
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,8 +1,122 @@
1
1
  {
2
- "name": "@cloudcome/utils-browser",
3
- "version": "0.0.0",
4
- "publishConfig": {
5
- "access": "public",
6
- "registry": "https://registry.npmjs.org/"
2
+ "name": "@cloudcome/utils-browser",
3
+ "version": "1.1.1",
4
+ "description": "cloudcome utils for browser",
5
+ "engines": {
6
+ "node": ">=22"
7
+ },
8
+ "engineStrict": true,
9
+ "sideEffects": false,
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.cjs"
15
+ },
16
+ "./package.json": "./package.json",
17
+ "./base64": {
18
+ "types": "./dist/base64.d.ts",
19
+ "import": "./dist/base64.mjs",
20
+ "require": "./dist/base64.cjs"
21
+ },
22
+ "./cache": {
23
+ "types": "./dist/cache.d.ts",
24
+ "import": "./dist/cache.mjs",
25
+ "require": "./dist/cache.cjs"
26
+ },
27
+ "./canvas": {
28
+ "types": "./dist/canvas.d.ts",
29
+ "import": "./dist/canvas.mjs",
30
+ "require": "./dist/canvas.cjs"
31
+ },
32
+ "./clipboard": {
33
+ "types": "./dist/clipboard.d.ts",
34
+ "import": "./dist/clipboard.mjs",
35
+ "require": "./dist/clipboard.cjs"
36
+ },
37
+ "./cookie": {
38
+ "types": "./dist/cookie.d.ts",
39
+ "import": "./dist/cookie.mjs",
40
+ "require": "./dist/cookie.cjs"
41
+ },
42
+ "./dom": {
43
+ "types": "./dist/dom.d.ts",
44
+ "import": "./dist/dom.mjs",
45
+ "require": "./dist/dom.cjs"
46
+ },
47
+ "./download": {
48
+ "types": "./dist/download.d.ts",
49
+ "import": "./dist/download.mjs",
50
+ "require": "./dist/download.cjs"
51
+ },
52
+ "./image": {
53
+ "types": "./dist/image.d.ts",
54
+ "import": "./dist/image.mjs",
55
+ "require": "./dist/image.cjs"
56
+ },
57
+ "./timer": {
58
+ "types": "./dist/timer.d.ts",
59
+ "import": "./dist/timer.mjs",
60
+ "require": "./dist/timer.cjs"
61
+ },
62
+ "./video": {
63
+ "types": "./dist/video.d.ts",
64
+ "import": "./dist/video.mjs",
65
+ "require": "./dist/video.cjs"
7
66
  }
8
- }
67
+ },
68
+ "typesVersions": {
69
+ "*": {
70
+ "base64": [
71
+ "./dist/base64.d.ts"
72
+ ],
73
+ "cache": [
74
+ "./dist/cache.d.ts"
75
+ ],
76
+ "canvas": [
77
+ "./dist/canvas.d.ts"
78
+ ],
79
+ "clipboard": [
80
+ "./dist/clipboard.d.ts"
81
+ ],
82
+ "cookie": [
83
+ "./dist/cookie.d.ts"
84
+ ],
85
+ "dom": [
86
+ "./dist/dom.d.ts"
87
+ ],
88
+ "download": [
89
+ "./dist/download.d.ts"
90
+ ],
91
+ "image": [
92
+ "./dist/image.d.ts"
93
+ ],
94
+ "timer": [
95
+ "./dist/timer.d.ts"
96
+ ],
97
+ "video": [
98
+ "./dist/video.d.ts"
99
+ ]
100
+ }
101
+ },
102
+ "main": "./dist/index.cjs",
103
+ "module": "./dist/index.mjs",
104
+ "types": "./dist/index.d.ts",
105
+ "dependencies": {
106
+ "@cloudcome/utils-core": "1.1.1"
107
+ },
108
+ "repository": "https://github.com/cloudcome/utils",
109
+ "keywords": [
110
+ "utils",
111
+ "cloudcome",
112
+ "utils-core",
113
+ "utils-vue",
114
+ "utils-react",
115
+ "utils-uni",
116
+ "utils-node",
117
+ "utils-browser"
118
+ ],
119
+ "homepage": "https://github.com/cloudcome/utils",
120
+ "license": "MIT",
121
+ "author": "云淡然 <hi@ydr.me> (https://ydr.me/)"
122
+ }
package/src/base64.ts ADDED
@@ -0,0 +1,25 @@
1
+ // @ref https://blog.csdn.net/m0_72642319/article/details/139743196
2
+
3
+ /**
4
+ * 【浏览器环境】将字符串编码为 Base64 格式
5
+ * @param input 要编码的字符串
6
+ * @returns 编码后的 Base64 字符串
7
+ * @remarks
8
+ * 在 Node.js 环境中使用 Buffer 实现,在浏览器环境中使用 TextEncoder 和 btoa 实现
9
+ */
10
+ export function encodeBase64(input: string) {
11
+ const encoder = new TextEncoder();
12
+ const unit8Array = encoder.encode(input);
13
+ return btoa(String.fromCharCode(...unit8Array));
14
+ }
15
+
16
+ /**
17
+ * 【浏览器环境】 将 Base64 字符串解码为原始字符串
18
+ * @param input 要解码的 Base64 字符串
19
+ * @returns 解码后的原始字符串
20
+ */
21
+ export function decodeBase64(input: string) {
22
+ const decoder = new TextDecoder();
23
+ const unit8Array = Uint8Array.from(atob(input), (c) => c.charCodeAt(0));
24
+ return decoder.decode(unit8Array);
25
+ }
package/src/cache.ts ADDED
@@ -0,0 +1,115 @@
1
+ import { AbstractCache, type TCacheOptions, type TCached } from '@cloudcome/utils-core/cache';
2
+ import type { MaybePromise } from '@cloudcome/utils-core/types';
3
+
4
+ /**
5
+ * 使用浏览器存储(localStorage 或 sessionStorage)实现的缓存类
6
+ * @template T - 缓存数据的类型
7
+ */
8
+ export class StorageCache<T> extends AbstractCache<T> {
9
+ /**
10
+ * 创建一个新的 StorageCache 实例
11
+ * @param storage - 使用的存储实现(localStorage 或 sessionStorage)
12
+ * @param namespace - 可选,用于为缓存键添加前缀的命名空间
13
+ */
14
+ constructor(
15
+ readonly storage: Storage,
16
+ readonly namespace = '',
17
+ ) {
18
+ super();
19
+ }
20
+
21
+ /**
22
+ * 通过ID获取缓存数据
23
+ * @param id - 要获取的缓存键
24
+ * @returns 如果找到且未过期则返回缓存数据,否则返回null
25
+ */
26
+ get(id: string): TCached<T> | null {
27
+ const { storage, namespace } = this;
28
+ const fullId = namespace ? `${namespace}:${id}` : id;
29
+
30
+ try {
31
+ const cachedString = storage.getItem(fullId);
32
+ if (!cachedString) return null;
33
+
34
+ const cached = JSON.parse(cachedString);
35
+
36
+ if (cached.createdAt + cached.maxAge < Date.now()) {
37
+ this.del(id);
38
+ return null;
39
+ }
40
+
41
+ return cached;
42
+ } catch (e) {
43
+ return null;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * 将数据存储到缓存中
49
+ * @param id - 存储数据使用的缓存键
50
+ * @param data - 要缓存的数据
51
+ * @param options - 可选的缓存配置
52
+ * @returns 成功返回true,存储失败返回false
53
+ */
54
+ set(id: string, data: T, options?: TCacheOptions) {
55
+ const { storage, namespace } = this;
56
+ const fullId = namespace ? `${namespace}:${id}` : id;
57
+
58
+ try {
59
+ storage.setItem(
60
+ fullId,
61
+ JSON.stringify({
62
+ id,
63
+ data,
64
+ createdAt: Date.now(),
65
+ maxAge: options?.maxAge || 0,
66
+ }),
67
+ );
68
+ } catch (cause) {
69
+ //
70
+ }
71
+ }
72
+
73
+ /**
74
+ * 通过ID删除缓存数据
75
+ * @param id - 要删除的缓存键
76
+ */
77
+ del(id: string) {
78
+ const { storage, namespace } = this;
79
+ const fullId = namespace ? `${namespace}:${id}` : id;
80
+
81
+ try {
82
+ storage.removeItem(fullId);
83
+ } catch (cause) {
84
+ //
85
+ }
86
+ }
87
+
88
+ clear() {
89
+ try {
90
+ this.storage.clear();
91
+ } catch (err) {
92
+ //
93
+ }
94
+ }
95
+ }
96
+
97
+ /**
98
+ * 创建一个使用 localStorage 的缓存实例
99
+ * @template T - 缓存数据的类型
100
+ * @param namespace - 可选,用于为缓存键添加前缀的命名空间
101
+ * @returns 使用 localStorage 的新 StorageCache 实例
102
+ */
103
+ export function createLocalCache<T>(namespace?: string): AbstractCache<T> {
104
+ return new StorageCache<T>(localStorage, namespace);
105
+ }
106
+
107
+ /**
108
+ * 创建一个使用 sessionStorage 的缓存实例
109
+ * @template T - 缓存数据的类型
110
+ * @param namespace - 可选,用于为缓存键添加前缀的命名空间
111
+ * @returns 使用 sessionStorage 的新 StorageCache 实例
112
+ */
113
+ export function createSessionCache<T>(namespace?: string): AbstractCache<T> {
114
+ return new StorageCache<T>(sessionStorage, namespace);
115
+ }
package/src/canvas.ts ADDED
@@ -0,0 +1,147 @@
1
+ import { objectDefaults } from '@cloudcome/utils-core/object';
2
+ import { imageLoad } from './image';
3
+
4
+ /**
5
+ * 将 Canvas 转换为 Base64 编码的字符串
6
+ * @param {HTMLCanvasElement} canvas - 需要转换的 Canvas 元素
7
+ * @param {string} [type] - 图片格式,默认为 'image/png'
8
+ * @param {number} [quality] - 图片质量,范围 0 到 1,仅适用于 'image/jpeg' 或 'image/webp'
9
+ * @returns {string} Base64 编码的图片数据
10
+ * @example
11
+ * const base64 = canvasToBase64(canvas, 'image/jpeg', 0.8);
12
+ */
13
+ export function canvasToBase64(canvas: HTMLCanvasElement, type?: string, quality?: number) {
14
+ return canvas.toDataURL(type, quality);
15
+ }
16
+
17
+ /**
18
+ * 将 Canvas 转换为 Blob 对象
19
+ * @param {HTMLCanvasElement} canvas - 需要转换的 Canvas 元素
20
+ * @param {string} [type] - 图片格式,默认为 'image/png'
21
+ * @param {number} [quality] - 图片质量,范围 0 到 1,仅适用于 'image/jpeg' 或 'image/webp'
22
+ * @returns {Promise<Blob>} 返回一个包含 Blob 对象的 Promise
23
+ * @example
24
+ * const blob = await canvasToBlob(canvas, 'image/jpeg', 0.8);
25
+ */
26
+ export async function canvasToBlob(canvas: HTMLCanvasElement, type?: string, quality?: number) {
27
+ return new Promise<Blob>((resolve, reject) => {
28
+ canvas.toBlob(
29
+ (blob) => {
30
+ if (blob) {
31
+ resolve(blob);
32
+ } else {
33
+ reject(new Error('canvas 导出二进制对象失败'));
34
+ }
35
+ },
36
+ type,
37
+ quality,
38
+ );
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Canvas 绘制图片的配置选项
44
+ */
45
+ export type CanvasDrawImageOptions = {
46
+ /**
47
+ * 源图片的左上角 x 坐标
48
+ * @type {number}
49
+ * @default 0
50
+ */
51
+ srcLeft?: number;
52
+ /**
53
+ * 源图片的左上角 y 坐标
54
+ * @type {number}
55
+ * @default 0
56
+ */
57
+ srcTop?: number;
58
+ /**
59
+ * 源图片的宽度
60
+ * @type {number}
61
+ * @default 图片的原始宽度
62
+ */
63
+ srcWidth?: number;
64
+ /**
65
+ * 源图片的高度
66
+ * @type {number}
67
+ * @default 图片的原始高度
68
+ */
69
+ srcHeight?: number;
70
+
71
+ /**
72
+ * 目标 Canvas 的左上角 x 坐标
73
+ * @type {number}
74
+ * @default 0
75
+ */
76
+ destLeft?: number;
77
+ /**
78
+ * 目标 Canvas 的左上角 y 坐标
79
+ * @type {number}
80
+ * @default 0
81
+ */
82
+ destTop?: number;
83
+ /**
84
+ * 目标 Canvas 的宽度
85
+ * @type {number}
86
+ * @default Canvas 的宽度
87
+ */
88
+ destWidth?: number;
89
+ /**
90
+ * 目标 Canvas 的高度
91
+ * @type {number}
92
+ * @default Canvas 的高度
93
+ */
94
+ destHeight?: number;
95
+ };
96
+
97
+ /**
98
+ * 在 Canvas 上绘制图片
99
+ * @param {HTMLCanvasElement} canvas - 目标 Canvas 元素
100
+ * @param {string} url - 图片的 URL
101
+ * @param {CanvasDrawImageOptions} [options] - 绘制图片的配置选项
102
+ * @returns {Promise<void>} 返回一个 Promise,表示绘制完成
103
+ * @example
104
+ * await canvasDrawImage(canvas, 'https://example.com/image.png', {
105
+ * srcLeft: 10,
106
+ * srcTop: 10,
107
+ * srcWidth: 100,
108
+ * srcHeight: 100,
109
+ * destLeft: 0,
110
+ * destTop: 0,
111
+ * destWidth: 200,
112
+ * destHeight: 200
113
+ * });
114
+ */
115
+ export async function canvasDrawImage(canvas: HTMLCanvasElement, url: string, options?: CanvasDrawImageOptions) {
116
+ const ctx = canvas.getContext('2d');
117
+ if (!ctx) throw new Error('canvas context is null');
118
+
119
+ const img = await imageLoad(url);
120
+ const defaults: CanvasDrawImageOptions = {
121
+ srcLeft: 0,
122
+ srcTop: 0,
123
+ srcWidth: img.width,
124
+ srcHeight: img.height,
125
+ destLeft: 0,
126
+ destTop: 0,
127
+ destWidth: canvas.width,
128
+ destHeight: canvas.height,
129
+ };
130
+ const { srcLeft, srcTop, srcWidth, srcHeight, destLeft, destTop, destWidth, destHeight } = objectDefaults(
131
+ options || {},
132
+ defaults,
133
+ ) as Required<CanvasDrawImageOptions>;
134
+ ctx.drawImage(
135
+ img,
136
+ // source
137
+ srcLeft,
138
+ srcTop,
139
+ srcWidth,
140
+ srcHeight,
141
+ // dest
142
+ destLeft,
143
+ destTop,
144
+ destWidth,
145
+ destHeight,
146
+ );
147
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * 将文本复制到剪贴板
3
+ * 该方法使用传统的 execCommand 方法实现文本复制
4
+ *
5
+ * @param text - 要复制到剪贴板的文本内容
6
+ * @returns void
7
+ *
8
+ * @example
9
+ * // 基本用法
10
+ * await copyText('Hello World');
11
+ *
12
+ * @example
13
+ * // 处理复制结果
14
+ * copyText('Hello World')
15
+ * .then(() => console.log('复制成功'))
16
+ * .catch(() => console.error('复制失败'));
17
+ */
18
+ export function copyText(text: string) {
19
+ const textArea = document.createElement('textarea');
20
+ textArea.value = text;
21
+ textArea.style.position = 'fixed';
22
+ textArea.style.left = '-9999px';
23
+ textArea.style.top = '-9999px';
24
+ document.body.appendChild(textArea);
25
+ textArea.focus();
26
+ textArea.select();
27
+ document.execCommand('copy');
28
+ document.body.removeChild(textArea);
29
+ }
package/src/cookie.ts ADDED
@@ -0,0 +1,118 @@
1
+ import type { TDateValue } from '@cloudcome/utils-core/date';
2
+ import { dateParse } from '@cloudcome/utils-core/date';
3
+
4
+ /**
5
+ * 获取指定名称的 Cookie 值。
6
+ * @param {string} name - Cookie 的名称。
7
+ * @returns {string} - 返回对应的 Cookie 值,如果不存在则返回空字符串。
8
+ */
9
+ export function cookieGet(name: string) {
10
+ const cookies = document.cookie.split(';');
11
+
12
+ for (let i = 0; i < cookies.length; i++) {
13
+ const cookie = cookies[i].trim();
14
+
15
+ if (cookie.startsWith(`${name}=`)) {
16
+ return decodeURIComponent(cookie.slice(name.length + 1));
17
+ }
18
+ }
19
+
20
+ return '';
21
+ }
22
+
23
+ /**
24
+ * 设置 Cookie。
25
+ * @param {string} name - Cookie 的名称。
26
+ * @param {string} value - Cookie 的值。
27
+ * @param {CookieOptions} [options] - 可选的 Cookie 配置项。
28
+ */
29
+ export type CookieOptions = {
30
+ /**
31
+ * Cookie 的过期时间,可以是日期字符串、时间戳或 `Date` 对象。
32
+ */
33
+ expires?: TDateValue;
34
+
35
+ /**
36
+ * Cookie 的路径,默认为当前路径。
37
+ */
38
+ path?: string;
39
+
40
+ /**
41
+ * Cookie 的域名,默认为当前域名。
42
+ */
43
+ domain?: string;
44
+
45
+ /**
46
+ * 是否启用安全传输(HTTPS)。
47
+ */
48
+ secure?: boolean;
49
+
50
+ /**
51
+ * SameSite 属性,可选值为 `'strict'`、`'lax'` 或 `'none'`。
52
+ */
53
+ sameSite?: 'strict' | 'lax' | 'none';
54
+
55
+ /**
56
+ * 是否启用 HttpOnly 标志,防止 JavaScript 访问。
57
+ */
58
+ httpOnly?: boolean;
59
+
60
+ /**
61
+ * Cookie 的最大存活时间(秒)。
62
+ */
63
+ maxAge?: number;
64
+ };
65
+
66
+ /**
67
+ * 设置 Cookie。
68
+ * @param {string} name - Cookie 的名称。
69
+ * @param {string} value - Cookie 的值。
70
+ * @param {CookieOptions} [options] - 可选的 Cookie 配置项。
71
+ */
72
+ export function cookieSet(name: string, value: string, options?: CookieOptions) {
73
+ const { expires, maxAge, path, domain, httpOnly, sameSite, secure } = options || {};
74
+ let cookie = `${name}=${encodeURIComponent(value)}`;
75
+
76
+ const expiresAt = expires ? dateParse(expires) : maxAge ? dateParse(Date.now() + maxAge) : null;
77
+ const metas: [string, string][] = [];
78
+
79
+ if (expiresAt) {
80
+ metas.push(['expires', expiresAt.toISOString()]);
81
+ }
82
+
83
+ if (path) {
84
+ metas.push(['path', path]);
85
+ }
86
+
87
+ if (domain) {
88
+ metas.push(['domain', domain]);
89
+ }
90
+
91
+ if (httpOnly) {
92
+ metas.push(['httpOnly', 'true']);
93
+ }
94
+
95
+ if (sameSite) {
96
+ metas.push(['sameSite', sameSite]);
97
+ }
98
+
99
+ if (secure) {
100
+ metas.push(['secure', 'true']);
101
+ }
102
+
103
+ for (const [key, value] of metas) {
104
+ cookie += `; ${key}=${value}`;
105
+ }
106
+
107
+ document.cookie = cookie;
108
+ }
109
+
110
+ /**
111
+ * 删除指定名称的 Cookie。
112
+ * @param {string} name - 要删除的 Cookie 名称。
113
+ */
114
+ export function cookieDel(name: string) {
115
+ cookieSet(name, '', {
116
+ expires: 0,
117
+ });
118
+ }
package/src/dom.ts ADDED
@@ -0,0 +1,48 @@
1
+ import { objectEach } from '@cloudcome/utils-core/object';
2
+
3
+ /**
4
+ * 表示 CSS 样式声明的类型,仅包含可用的字符串或数字类型的属性
5
+ * @typedef {Object} TStyle
6
+ * @property {string | number} [K] - CSS 样式属性,K 为 CSSStyleDeclaration 的键名,且值为字符串或数字类型
7
+ */
8
+ export type TStyle = {
9
+ [K in keyof CSSStyleDeclaration as K extends number
10
+ ? never
11
+ : CSSStyleDeclaration[K] extends string | number
12
+ ? K
13
+ : never]: CSSStyleDeclaration[K];
14
+ };
15
+
16
+ /**
17
+ * 设置元素的样式
18
+ * @param {HTMLElement} el - 需要设置样式的 HTML 元素
19
+ * @param {string | Partial<TStyle> | Record<string, string>} style - 样式字符串或样式对象
20
+ * @example
21
+ * // 设置 body 元素的颜色为红色,并设置一个自定义变量
22
+ * setStyle(document.body, { color: 'red', '--var': 'value' });
23
+ * @example
24
+ * // 使用字符串设置样式
25
+ * setStyle(document.body, 'color: red; --var: value;');
26
+ */
27
+ export function setStyle(el: HTMLElement, style: string | Partial<TStyle> | Record<string, string>) {
28
+ if (typeof style === 'string') {
29
+ el.style.cssText = style;
30
+ } else {
31
+ objectEach(style, (value, key) => {
32
+ el.style.setProperty(key as string, value as string | null);
33
+ });
34
+ }
35
+ }
36
+
37
+ /**
38
+ * 获取元素的指定样式值
39
+ * @param {HTMLElement} el - 需要获取样式的 HTML 元素
40
+ * @param {keyof TStyle} style - 需要获取的样式属性
41
+ * @returns {string} 返回指定样式的值
42
+ * @example
43
+ * // 获取 body 元素的颜色
44
+ * const color = getStyle(document.body, 'color');
45
+ */
46
+ export function getStyle(el: HTMLElement, style: keyof TStyle) {
47
+ return window.getComputedStyle(el).getPropertyValue(style);
48
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 下载 URL
3
+ * @param {string} url
4
+ * @param {string} filename
5
+ */
6
+ export function downloadURL(url: string, filename?: string) {
7
+ const a = document.createElement('a');
8
+ a.href = url;
9
+ a.download = filename || '';
10
+ a.click();
11
+ }
12
+
13
+ /**
14
+ * 下载 Blob 对象
15
+ * @param blob Blob 对象
16
+ * @param filename 文件名
17
+ */
18
+ export function downloadBlob(blob: Blob, filename?: string) {
19
+ const url = URL.createObjectURL(blob);
20
+ downloadURL(url, filename);
21
+ URL.revokeObjectURL(url);
22
+ }