styimat 1.3.0 → 1.5.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 +250 -24
- package/package.json +2 -2
- package/styimat.js +398 -28
- package/styimat.min.js +181 -22
package/README.md
CHANGED
|
@@ -1,37 +1,52 @@
|
|
|
1
1
|
# styimat
|
|
2
|
+
[](https://gitee.com/wxy6987/styimat/stargazers)
|
|
3
|
+
[](https://gitee.com/wxy6987/styimat/members)
|
|
2
4
|
|
|
3
|
-
一个功能强大的 CSS 变量预处理库,支持嵌套规则、Lab/LCH
|
|
5
|
+
一个功能强大的 CSS 变量预处理库,支持嵌套规则、Lab/LCH 颜色空间转换、Display P3 广色域和增强的数学计算功能。
|
|
4
6
|
|
|
5
|
-
##
|
|
7
|
+
## 安装方式
|
|
8
|
+
|
|
9
|
+
### 1. Git 克隆(推荐)
|
|
10
|
+
```bash
|
|
11
|
+
# 克隆主仓库
|
|
12
|
+
git clone https://gitee.com/wxy6987/styimat.git
|
|
6
13
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- 🔧 **变量系统** - 类似 Sass 的变量系统,支持作用域变量
|
|
10
|
-
- 🏗️ **嵌套规则** - 支持 Sass 风格的嵌套选择器
|
|
11
|
-
- 📱 **十六进制语法** - 支持 `lab#L16A16B16` 和 `lch#L16C16H` 简洁语法
|
|
12
|
-
- ⚡ **轻量高效** - 无依赖,压缩后仅约 20KB
|
|
13
|
-
- 🔄 **多种使用方式** - 浏览器、Node.js、命令行均可使用
|
|
14
|
+
# 进入项目目录
|
|
15
|
+
cd styimat
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
# 安装依赖
|
|
18
|
+
npm install
|
|
19
|
+
```
|
|
16
20
|
|
|
17
|
-
###
|
|
21
|
+
### 2. 直接下载 ZIP
|
|
22
|
+
- [点击下载最新版本](https://gitee.com/wxy6987/styimat/repository/archive/main.zip)
|
|
18
23
|
|
|
24
|
+
### 3. NPM 安装
|
|
19
25
|
```bash
|
|
20
26
|
npm install styimat
|
|
21
27
|
```
|
|
22
28
|
|
|
23
|
-
### CDN
|
|
24
|
-
|
|
29
|
+
### 4. CDN 引入
|
|
25
30
|
```html
|
|
31
|
+
<!-- unpkg -->
|
|
26
32
|
<script src="https://unpkg.com/styimat"></script>
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### CDN (jsdelivr)
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
<!-- jsdelivr -->
|
|
32
35
|
<script src="https://cdn.jsdelivr.net/npm/styimat/styimat.min.js"></script>
|
|
33
36
|
```
|
|
34
37
|
|
|
38
|
+
## 特性
|
|
39
|
+
|
|
40
|
+
- **Lab/LCH 颜色支持** - 将 Lab 和 LCH 颜色转换为 CSS 兼容的 RGB
|
|
41
|
+
- **广色域显示** - 自动检测并支持 Display P3 广色域显示器
|
|
42
|
+
- **变量系统** - 类似 Sass 的变量系统,支持作用域变量
|
|
43
|
+
-️ **嵌套规则** - 支持 Sass 风格的嵌套选择器
|
|
44
|
+
- **十六进制语法** - 支持 `lab#L16A16B16` 和 `lch#L16C16H` 简洁语法
|
|
45
|
+
- **增强数学计算** - 支持 `math()` 函数和复杂数学表达式
|
|
46
|
+
- **轻量高效** - 无依赖,压缩后仅约 20KB
|
|
47
|
+
- **多种使用方式** - 浏览器、Node.js、命令行均可使用
|
|
48
|
+
- **灵活API** - 支持函数调用、模板标签、对象配置等多种用法
|
|
49
|
+
|
|
35
50
|
## 快速开始
|
|
36
51
|
|
|
37
52
|
### 浏览器中使用
|
|
@@ -108,6 +123,123 @@ npm install -g styimat
|
|
|
108
123
|
styimat input.css output.css
|
|
109
124
|
```
|
|
110
125
|
|
|
126
|
+
## 高级用法
|
|
127
|
+
|
|
128
|
+
### 1. 作为函数直接调用
|
|
129
|
+
|
|
130
|
+
`styimat` 本身是一个可调用的函数,支持多种调用方式:
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
// 方式1:直接传入CSS字符串
|
|
134
|
+
const css1 = styimat(`
|
|
135
|
+
$primary: lab(54.7 77.9 80.1);
|
|
136
|
+
.button { color: $primary; }
|
|
137
|
+
`);
|
|
138
|
+
|
|
139
|
+
// 方式2:传入配置对象(返回函数本身,可以链式调用)
|
|
140
|
+
styimat({
|
|
141
|
+
enableP3: true,
|
|
142
|
+
enableMath: true,
|
|
143
|
+
mathPrecision: 8
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// 方式3:无参数调用(自动处理页面中所有标记的<style>标签)
|
|
147
|
+
styimat();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 2. 作为模板标签使用
|
|
151
|
+
|
|
152
|
+
`styimat` 可以作为ES6模板字符串的标签函数,提供更简洁的语法:
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
// 基本模板标签用法
|
|
156
|
+
const css = styimat`
|
|
157
|
+
$primary: lab(54.7 77.9 80.1);
|
|
158
|
+
$secondary: lch(44.7 67.9 210);
|
|
159
|
+
|
|
160
|
+
.button {
|
|
161
|
+
background: $primary;
|
|
162
|
+
color: white;
|
|
163
|
+
|
|
164
|
+
&:hover {
|
|
165
|
+
background: $secondary;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
`;
|
|
169
|
+
|
|
170
|
+
// 模板标签支持插值
|
|
171
|
+
const theme = 'dark';
|
|
172
|
+
const cssWithVars = styimat`
|
|
173
|
+
$primary: ${theme === 'dark' ? 'lab(30 40 50)' : 'lab(70 20 -10)'};
|
|
174
|
+
|
|
175
|
+
body {
|
|
176
|
+
background: $primary;
|
|
177
|
+
}
|
|
178
|
+
`;
|
|
179
|
+
|
|
180
|
+
// 复杂的插值示例
|
|
181
|
+
const spacing = 1.5;
|
|
182
|
+
const cssComplex = styimat`
|
|
183
|
+
$base-spacing: ${spacing}rem;
|
|
184
|
+
$large-spacing: math(${spacing} * 2);
|
|
185
|
+
|
|
186
|
+
.container {
|
|
187
|
+
padding: $base-spacing;
|
|
188
|
+
margin: $large-spacing;
|
|
189
|
+
}
|
|
190
|
+
`;
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 3. 作为对象方法调用
|
|
194
|
+
|
|
195
|
+
除了函数调用,`styimat` 还提供了对象方法:
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
// 1. 转换CSS
|
|
199
|
+
const converted = styimat.convert(cssString, config);
|
|
200
|
+
|
|
201
|
+
// 2. 应用到页面
|
|
202
|
+
const styleElement = styimat.apply(cssString, config);
|
|
203
|
+
|
|
204
|
+
// 3. 配置全局设置
|
|
205
|
+
styimat.config({
|
|
206
|
+
enableP3: true,
|
|
207
|
+
enableMath: true,
|
|
208
|
+
indentSize: 2
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// 4. 使用工具方法
|
|
212
|
+
const mathResult = styimat.math.evaluate('100px / 2'); // "50px"
|
|
213
|
+
const rgbColor = styimat.colorUtils.labToRGB(54.7, 77.9, 80.1);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 4. 混合使用示例
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
// 先配置,然后使用模板标签
|
|
220
|
+
styimat.config({ enableP3: true });
|
|
221
|
+
|
|
222
|
+
const designSystem = styimat`
|
|
223
|
+
/* 设计系统变量 */
|
|
224
|
+
$primary: lab#8CFF80;
|
|
225
|
+
$secondary: lch#6CFF180;
|
|
226
|
+
$spacing-unit: 1rem;
|
|
227
|
+
|
|
228
|
+
/* 组件样式 */
|
|
229
|
+
.btn {
|
|
230
|
+
padding: $spacing-unit;
|
|
231
|
+
background: $primary;
|
|
232
|
+
|
|
233
|
+
&.secondary {
|
|
234
|
+
background: $secondary;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
`;
|
|
238
|
+
|
|
239
|
+
// 应用到页面
|
|
240
|
+
styimat.apply(designSystem);
|
|
241
|
+
```
|
|
242
|
+
|
|
111
243
|
## 语法指南
|
|
112
244
|
|
|
113
245
|
### 变量定义
|
|
@@ -125,6 +257,24 @@ $font-family: 'Inter', sans-serif;
|
|
|
125
257
|
}
|
|
126
258
|
```
|
|
127
259
|
|
|
260
|
+
### Math 计算语法
|
|
261
|
+
|
|
262
|
+
```css
|
|
263
|
+
/* math() 函数 */
|
|
264
|
+
.element {
|
|
265
|
+
width: math(100% / 3);
|
|
266
|
+
height: math(200px + 30px);
|
|
267
|
+
padding: math(2rem * 1.5);
|
|
268
|
+
margin: math(calc(100vh - 200px) / 2);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* 支持单位运算 */
|
|
272
|
+
.container {
|
|
273
|
+
font-size: math(16px * 1.125); /* 18px */
|
|
274
|
+
gap: math(24px + 1rem); /* 支持混合单位 */
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
128
278
|
### Lab 颜色语法
|
|
129
279
|
|
|
130
280
|
```css
|
|
@@ -188,10 +338,18 @@ LCH 颜色使用 `lch#` 前缀,后跟 6 个字符(最后1-3位是十进制
|
|
|
188
338
|
|
|
189
339
|
.header {
|
|
190
340
|
font-size: 2rem;
|
|
341
|
+
|
|
342
|
+
.title {
|
|
343
|
+
color: lab(20 40 60);
|
|
344
|
+
}
|
|
191
345
|
}
|
|
192
346
|
|
|
193
347
|
@media (min-width: 768px) {
|
|
194
348
|
padding: 2rem;
|
|
349
|
+
|
|
350
|
+
.header {
|
|
351
|
+
font-size: 3rem;
|
|
352
|
+
}
|
|
195
353
|
}
|
|
196
354
|
}
|
|
197
355
|
```
|
|
@@ -203,10 +361,12 @@ LCH 颜色使用 `lch#` 前缀,后跟 6 个字符(最后1-3位是十进制
|
|
|
203
361
|
$base-color: lab(54.7 77.9 80.1);
|
|
204
362
|
$text-color: lch(20 30 270);
|
|
205
363
|
$border-color: $base-color;
|
|
364
|
+
$padding-large: math(2rem * 1.5);
|
|
206
365
|
|
|
207
366
|
.element {
|
|
208
367
|
color: $text-color;
|
|
209
368
|
border: 1px solid $border-color;
|
|
369
|
+
padding: $padding-large;
|
|
210
370
|
}
|
|
211
371
|
```
|
|
212
372
|
|
|
@@ -230,14 +390,23 @@ styimat.config({
|
|
|
230
390
|
convertLabToRGB: true,
|
|
231
391
|
convertLchToRGB: true,
|
|
232
392
|
enableP3: true,
|
|
393
|
+
enableMath: true,
|
|
394
|
+
mathPrecision: 6,
|
|
233
395
|
indentSize: 2,
|
|
234
396
|
enableNesting: true
|
|
235
397
|
});
|
|
236
398
|
|
|
399
|
+
// 数学工具
|
|
400
|
+
styimat.math.evaluate('100px / 2'); // "50px"
|
|
401
|
+
styimat.math.evaluate('(16px * 1.5) + 4px'); // "28px"
|
|
402
|
+
|
|
237
403
|
// 颜色工具
|
|
238
404
|
const rgb = styimat.colorUtils.labToRGB(54.7, 77.9, 80.1);
|
|
239
405
|
const p3 = styimat.colorUtils.labToP3(54.7, 77.9, 80.1);
|
|
240
406
|
const lab = styimat.colorUtils.lchToLab(54.7, 78.9, 38.5);
|
|
407
|
+
|
|
408
|
+
// 解析颜色
|
|
409
|
+
const colorInfo = styimat.colorUtils.parseColor('lab(54.7 77.9 80.1 / 0.8)');
|
|
241
410
|
```
|
|
242
411
|
|
|
243
412
|
### 配置选项
|
|
@@ -254,6 +423,8 @@ const lab = styimat.colorUtils.lchToLab(54.7, 78.9, 38.5);
|
|
|
254
423
|
| `convertLabToRGB` | boolean | `true` | 是否转换 Lab 颜色为 RGB |
|
|
255
424
|
| `convertLchToRGB` | boolean | `true` | 是否转换 LCH 颜色为 RGB |
|
|
256
425
|
| `enableP3` | boolean | `true` | 是否启用 Display P3 广色域支持 |
|
|
426
|
+
| `enableMath` | boolean | `true` | 是否启用 `math()` 函数增强 |
|
|
427
|
+
| `mathPrecision` | number | `6` | 数学计算的精度 |
|
|
257
428
|
|
|
258
429
|
## 示例
|
|
259
430
|
|
|
@@ -271,7 +442,7 @@ $border-radius: 0.5rem;
|
|
|
271
442
|
.button {
|
|
272
443
|
background-color: $brand-primary;
|
|
273
444
|
color: white;
|
|
274
|
-
padding: $spacing-unit
|
|
445
|
+
padding: $spacing-unit math($spacing-unit * 2);
|
|
275
446
|
border-radius: $border-radius;
|
|
276
447
|
border: 2px solid lab(44.7 67.9 70.1);
|
|
277
448
|
|
|
@@ -281,8 +452,8 @@ $border-radius: 0.5rem;
|
|
|
281
452
|
}
|
|
282
453
|
|
|
283
454
|
&.large {
|
|
284
|
-
padding:
|
|
285
|
-
font-size: 1.
|
|
455
|
+
padding: math($spacing-unit * 1.5) math($spacing-unit * 3);
|
|
456
|
+
font-size: math(1rem * 1.25);
|
|
286
457
|
}
|
|
287
458
|
}
|
|
288
459
|
|
|
@@ -293,6 +464,7 @@ $border-radius: 0.5rem;
|
|
|
293
464
|
|
|
294
465
|
@media (max-width: 768px) {
|
|
295
466
|
padding: 0 $spacing-unit;
|
|
467
|
+
font-size: math(16px * 0.9);
|
|
296
468
|
}
|
|
297
469
|
}
|
|
298
470
|
```
|
|
@@ -318,18 +490,72 @@ $primary-transparent: lab(55 190 0 / 0.8);
|
|
|
318
490
|
.card {
|
|
319
491
|
background: linear-gradient(135deg, $primary, $secondary);
|
|
320
492
|
border: 1px solid $accent;
|
|
493
|
+
width: math(100% / 3);
|
|
321
494
|
}
|
|
322
495
|
}
|
|
323
496
|
```
|
|
324
497
|
|
|
498
|
+
### Math() 函数高级示例
|
|
499
|
+
|
|
500
|
+
```css
|
|
501
|
+
/* 复杂数学计算 */
|
|
502
|
+
.grid {
|
|
503
|
+
--columns: 12;
|
|
504
|
+
--gap: 1rem;
|
|
505
|
+
|
|
506
|
+
.col-4 {
|
|
507
|
+
width: math(calc(100% / var(--columns)) * 4);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.col-6 {
|
|
511
|
+
width: math(calc(100% / var(--columns)) * 6 - var(--gap));
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.responsive {
|
|
516
|
+
font-size: math(clamp(16px, 2vw + 8px, 24px));
|
|
517
|
+
padding: math(max(1rem, 2vh));
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.aspect-ratio {
|
|
521
|
+
height: math(100vw / 16 * 9); /* 16:9 宽高比 */
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
## Git 仓库
|
|
526
|
+
|
|
527
|
+
- **主仓库**: [https://gitee.com/wxy6987/styimat](https://gitee.com/wxy6987/styimat)
|
|
528
|
+
- **ZIP 下载**: [https://gitee.com/wxy6987/styimat/repository/archive/main.zip](https://gitee.com/wxy6987/styimat/repository/archive/main.zip)
|
|
529
|
+
- **Issues**: [问题反馈](https://gitee.com/wxy6987/styimat/issues)
|
|
530
|
+
- **Pull Requests**: [贡献代码](https://gitee.com/wxy6987/styimat/pulls)
|
|
531
|
+
|
|
532
|
+
## 贡献指南
|
|
533
|
+
|
|
534
|
+
欢迎贡献代码!请遵循以下步骤:
|
|
535
|
+
|
|
536
|
+
1. **Fork 本仓库**
|
|
537
|
+
2. **创建特性分支**
|
|
538
|
+
```bash
|
|
539
|
+
git checkout -b feature/AmazingFeature
|
|
540
|
+
```
|
|
541
|
+
3. **提交更改**
|
|
542
|
+
```bash
|
|
543
|
+
git commit -m 'Add some AmazingFeature'
|
|
544
|
+
```
|
|
545
|
+
4. **推送到分支**
|
|
546
|
+
```bash
|
|
547
|
+
git push origin feature/AmazingFeature
|
|
548
|
+
```
|
|
549
|
+
5. **提交 Pull Request**
|
|
550
|
+
|
|
325
551
|
## 许可证
|
|
326
552
|
|
|
327
553
|
MIT © 王小玗 2025
|
|
328
554
|
|
|
329
|
-
##
|
|
555
|
+
## 支持
|
|
330
556
|
|
|
331
|
-
|
|
557
|
+
如果发现 bug 或有功能建议,请在 [Gitee Issues](https://gitee.com/wxy6987/styimat/issues) 中创建 Issue。
|
|
332
558
|
|
|
333
|
-
|
|
559
|
+
---
|
|
334
560
|
|
|
335
|
-
|
|
561
|
+
**如果这个项目对你有帮助,请给个 [](https://gitee.com/wxy6987/styimat)**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "styimat",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.5.0",
|
|
4
|
+
"description": "一个高效的CSS变量预处理库,支持Lab/LCH颜色空间自动转换、嵌套选择器和Display P3广色域,让现代CSS开发更简洁强大。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|
|
7
7
|
"preprocessor",
|
package/styimat.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* MIT License
|
|
3
|
+
* Copyright (c) 2025 王小玗
|
|
4
|
+
*/
|
|
1
5
|
/**
|
|
2
6
|
* CSS 变量预处理库 - 增强版
|
|
3
7
|
* 支持 CSS 变量预处理、嵌套选择器和嵌套变量
|
|
4
8
|
* 支持 Lab 和 LCH 颜色空间转换为 RGB(CSS标准格式)
|
|
5
9
|
* 支持 lab# 和 lch# 十六进制语法
|
|
6
10
|
* 支持 Display P3 广色域显示器
|
|
11
|
+
* 增强 math() 函数,支持复杂数学计算
|
|
7
12
|
*/
|
|
8
13
|
(function(root, factory) {
|
|
9
14
|
if (typeof define === 'function' && define.amd) {
|
|
@@ -26,9 +31,11 @@
|
|
|
26
31
|
enableNesting: true,
|
|
27
32
|
autoProcessStyleTags: true,
|
|
28
33
|
styleTagAttribute: 'e',
|
|
29
|
-
convertLabToRGB: true,
|
|
30
|
-
convertLchToRGB: true,
|
|
31
|
-
enableP3: true,
|
|
34
|
+
convertLabToRGB: true,
|
|
35
|
+
convertLchToRGB: true,
|
|
36
|
+
enableP3: true,
|
|
37
|
+
enableMath: true, // 启用math()函数增强
|
|
38
|
+
mathPrecision: 6, // 数学计算精度
|
|
32
39
|
};
|
|
33
40
|
|
|
34
41
|
// 全局P3支持检测结果
|
|
@@ -181,6 +188,252 @@
|
|
|
181
188
|
return -1;
|
|
182
189
|
}
|
|
183
190
|
|
|
191
|
+
/**
|
|
192
|
+
* 增强的数学表达式解析和计算
|
|
193
|
+
* @param {string} expression - 数学表达式
|
|
194
|
+
* @param {Object} config - 配置对象
|
|
195
|
+
* @returns {string} 计算结果
|
|
196
|
+
*/
|
|
197
|
+
function evaluateMathExpression(expression, config) {
|
|
198
|
+
// 如果禁用math()增强,则返回原始表达式
|
|
199
|
+
if (!config.enableMath) {
|
|
200
|
+
return `math(${expression})`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
// 清理表达式:移除空白字符
|
|
205
|
+
let cleanExpr = expression.replace(/\s+/g, '');
|
|
206
|
+
|
|
207
|
+
// 解析数学表达式
|
|
208
|
+
const result = parseMathExpression(cleanExpr, config);
|
|
209
|
+
|
|
210
|
+
// 如果结果包含单位,保留原始格式
|
|
211
|
+
if (hasUnits(cleanExpr)) {
|
|
212
|
+
// 处理带单位的表达式
|
|
213
|
+
return processUnitExpression(cleanExpr, result);
|
|
214
|
+
} else {
|
|
215
|
+
// 纯数字表达式,直接计算结果
|
|
216
|
+
return roundNumber(result, config.mathPrecision);
|
|
217
|
+
}
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.warn('math()表达式解析失败:', expression, error);
|
|
220
|
+
return `math(${expression})`;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 解析数学表达式
|
|
226
|
+
* @param {string} expr - 清理后的表达式
|
|
227
|
+
* @param {Object} config - 配置对象
|
|
228
|
+
* @returns {number} 计算结果
|
|
229
|
+
*/
|
|
230
|
+
function parseMathExpression(expr, config) {
|
|
231
|
+
// 处理括号
|
|
232
|
+
while (expr.includes('(') && expr.includes(')')) {
|
|
233
|
+
const start = expr.lastIndexOf('(');
|
|
234
|
+
const end = expr.indexOf(')', start);
|
|
235
|
+
|
|
236
|
+
if (end === -1) break;
|
|
237
|
+
|
|
238
|
+
const inner = expr.substring(start + 1, end);
|
|
239
|
+
const innerResult = parseMathExpression(inner, config);
|
|
240
|
+
|
|
241
|
+
expr = expr.substring(0, start) + innerResult + expr.substring(end + 1);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// 现在expr应该没有括号了
|
|
245
|
+
return evaluateSimpleExpression(expr, config);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 评估简单表达式(无括号)
|
|
250
|
+
* @param {string} expr - 简单表达式
|
|
251
|
+
* @param {Object} config - 配置对象
|
|
252
|
+
* @returns {number} 计算结果
|
|
253
|
+
*/
|
|
254
|
+
function evaluateSimpleExpression(expr, config) {
|
|
255
|
+
// 处理操作符优先级:乘除优先于加减
|
|
256
|
+
const operators = [
|
|
257
|
+
{ regex: /([\d.]+(?:[a-zA-Z%]+)?)\*([\d.]+(?:[a-zA-Z%]+)?)/, handler: multiply },
|
|
258
|
+
{ regex: /([\d.]+(?:[a-zA-Z%]+)?)\/([\d.]+(?:[a-zA-Z%]+)?)/, handler: divide },
|
|
259
|
+
{ regex: /([\d.]+(?:[a-zA-Z%]+)?)\+([\d.]+(?:[a-zA-Z%]+)?)/, handler: add },
|
|
260
|
+
{ regex: /([\d.]+(?:[a-zA-Z%]+)?)-([\d.]+(?:[a-zA-Z%]+)?)/, handler: subtract }
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
let lastExpr = expr;
|
|
264
|
+
|
|
265
|
+
// 按照优先级处理操作符
|
|
266
|
+
for (const op of operators) {
|
|
267
|
+
let match;
|
|
268
|
+
while ((match = expr.match(op.regex)) !== null) {
|
|
269
|
+
const left = parseValueWithUnit(match[1]);
|
|
270
|
+
const right = parseValueWithUnit(match[2]);
|
|
271
|
+
const result = op.handler(left, right);
|
|
272
|
+
|
|
273
|
+
// 替换匹配的部分
|
|
274
|
+
expr = expr.substring(0, match.index) +
|
|
275
|
+
result.value +
|
|
276
|
+
expr.substring(match.index + match[0].length);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// 如果表达式无法进一步简化,尝试解析为数字
|
|
281
|
+
if (expr !== lastExpr) {
|
|
282
|
+
return evaluateSimpleExpression(expr, config);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// 解析最终结果
|
|
286
|
+
const parsed = parseValueWithUnit(expr);
|
|
287
|
+
return parsed.value;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* 解析带单位的数值
|
|
292
|
+
* @param {string} str - 字符串值
|
|
293
|
+
* @returns {Object} {value: number, unit: string}
|
|
294
|
+
*/
|
|
295
|
+
function parseValueWithUnit(str) {
|
|
296
|
+
// 匹配数值和单位
|
|
297
|
+
const match = str.match(/^([\d.]+)([a-zA-Z%]*)$/);
|
|
298
|
+
|
|
299
|
+
if (!match) {
|
|
300
|
+
throw new Error(`无法解析值: ${str}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const value = parseFloat(match[1]);
|
|
304
|
+
const unit = match[2] || '';
|
|
305
|
+
|
|
306
|
+
return { value, unit };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* 检查表达式是否包含单位
|
|
311
|
+
* @param {string} expr - 表达式
|
|
312
|
+
* @returns {boolean} 是否包含单位
|
|
313
|
+
*/
|
|
314
|
+
function hasUnits(expr) {
|
|
315
|
+
return /[a-zA-Z%]/.test(expr);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* 处理带单位的表达式
|
|
320
|
+
* @param {string} originalExpr - 原始表达式
|
|
321
|
+
* @param {number} result - 计算结果
|
|
322
|
+
* @returns {string} 处理后的表达式
|
|
323
|
+
*/
|
|
324
|
+
function processUnitExpression(originalExpr, result) {
|
|
325
|
+
// 提取原始表达式中的单位
|
|
326
|
+
const unitMatch = originalExpr.match(/([a-zA-Z%]+)(?!.*[a-zA-Z%])/);
|
|
327
|
+
|
|
328
|
+
if (unitMatch) {
|
|
329
|
+
return result + unitMatch[1];
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// 如果没有明确单位,检查是否为百分比
|
|
333
|
+
if (originalExpr.includes('%')) {
|
|
334
|
+
return result + '%';
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// 默认为像素
|
|
338
|
+
return result + 'px';
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// 数学运算函数
|
|
342
|
+
function multiply(a, b) {
|
|
343
|
+
if (a.unit === b.unit || (!a.unit && !b.unit)) {
|
|
344
|
+
return { value: a.value * b.value, unit: a.unit || b.unit };
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// 单位不匹配,返回原始表达式
|
|
348
|
+
return { value: `${a.value}${a.unit}*${b.value}${b.unit}`, unit: '' };
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function divide(a, b) {
|
|
352
|
+
if (b.value === 0) {
|
|
353
|
+
throw new Error('除以零');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (a.unit && !b.unit) {
|
|
357
|
+
// 如 100px / 2
|
|
358
|
+
return { value: a.value / b.value, unit: a.unit };
|
|
359
|
+
} else if (a.unit === b.unit) {
|
|
360
|
+
// 如 100px / 2px
|
|
361
|
+
return { value: a.value / b.value, unit: '' };
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// 单位不匹配,返回原始表达式
|
|
365
|
+
return { value: `${a.value}${a.unit}/${b.value}${b.unit}`, unit: '' };
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function add(a, b) {
|
|
369
|
+
if (a.unit === b.unit) {
|
|
370
|
+
return { value: a.value + b.value, unit: a.unit };
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// 单位不匹配,返回原始表达式
|
|
374
|
+
return { value: `${a.value}${a.unit}+${b.value}${b.unit}`, unit: '' };
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function subtract(a, b) {
|
|
378
|
+
if (a.unit === b.unit) {
|
|
379
|
+
return { value: a.value - b.value, unit: a.unit };
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// 单位不匹配,返回原始表达式
|
|
383
|
+
return { value: `${a.value}${a.unit}-${b.value}${b.unit}`, unit: '' };
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* 四舍五入到指定精度
|
|
388
|
+
* @param {number} num - 要四舍五入的数字
|
|
389
|
+
* @param {number} precision - 精度
|
|
390
|
+
* @returns {string} 四舍五入后的数字字符串
|
|
391
|
+
*/
|
|
392
|
+
function roundNumber(num, precision = 6) {
|
|
393
|
+
const factor = Math.pow(10, precision);
|
|
394
|
+
const rounded = Math.round(num * factor) / factor;
|
|
395
|
+
|
|
396
|
+
// 移除不必要的尾随零
|
|
397
|
+
const str = rounded.toString();
|
|
398
|
+
if (str.includes('.')) {
|
|
399
|
+
return str.replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '');
|
|
400
|
+
}
|
|
401
|
+
return str;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* 处理所有的math()函数
|
|
406
|
+
* @param {string} cssValue - CSS属性值
|
|
407
|
+
* @param {Object} config - 配置对象
|
|
408
|
+
* @returns {string} 转换后的CSS值
|
|
409
|
+
*/
|
|
410
|
+
function processMathFunctions(cssValue, config) {
|
|
411
|
+
if (!config.enableMath) {
|
|
412
|
+
return cssValue;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
let result = cssValue;
|
|
416
|
+
|
|
417
|
+
// 匹配math()函数
|
|
418
|
+
const mathRegex = /math\(([^)]+)\)/gi;
|
|
419
|
+
|
|
420
|
+
// 递归处理嵌套的math()函数
|
|
421
|
+
const processMath = (str) => {
|
|
422
|
+
return str.replace(mathRegex, (match, expression) => {
|
|
423
|
+
return evaluateMathExpression(expression, config);
|
|
424
|
+
});
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// 递归处理,直到没有更多math()函数
|
|
428
|
+
let lastResult;
|
|
429
|
+
do {
|
|
430
|
+
lastResult = result;
|
|
431
|
+
result = processMath(result);
|
|
432
|
+
} while (result !== lastResult && result.includes('math('));
|
|
433
|
+
|
|
434
|
+
return result;
|
|
435
|
+
}
|
|
436
|
+
|
|
184
437
|
/**
|
|
185
438
|
* 解析并转换所有的 Lab 和 LCH 颜色(全局一次性处理)
|
|
186
439
|
* @param {string} cssValue - CSS属性值
|
|
@@ -616,21 +869,32 @@
|
|
|
616
869
|
}
|
|
617
870
|
|
|
618
871
|
/**
|
|
619
|
-
* 处理CSS值,根据配置转换LAB
|
|
872
|
+
* 处理CSS值,根据配置转换LAB、LCH颜色和math()函数
|
|
620
873
|
* @param {string} value - CSS属性值
|
|
621
874
|
* @param {Object} config - 配置对象
|
|
622
875
|
* @returns {string} 处理后的值
|
|
623
876
|
*/
|
|
624
877
|
function processCSSValue(value, config) {
|
|
625
|
-
|
|
626
|
-
|
|
878
|
+
let result = value;
|
|
879
|
+
|
|
880
|
+
// 1. 首先处理math()函数
|
|
881
|
+
if (config.enableMath) {
|
|
882
|
+
result = processMathFunctions(result, config);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// 2. 然后处理LAB和LCH颜色
|
|
886
|
+
if (config.convertLabToRGB || config.convertLchToRGB) {
|
|
887
|
+
result = convertAllLabLchColors(result, config);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
return result;
|
|
627
891
|
}
|
|
628
892
|
|
|
629
893
|
// 私有方法:提取变量定义并移除(支持嵌套作用域)
|
|
630
894
|
function extractVariablesAndCSS(cssText, config) {
|
|
631
895
|
const lines = cssText.split('\n');
|
|
632
896
|
const globalVariables = {};
|
|
633
|
-
const selectorVariables = new Map();
|
|
897
|
+
const selectorVariables = new Map();
|
|
634
898
|
let cssWithoutVars = '';
|
|
635
899
|
let currentSelector = null;
|
|
636
900
|
let inSelectorBlock = false;
|
|
@@ -644,8 +908,8 @@
|
|
|
644
908
|
|
|
645
909
|
if (varMatch) {
|
|
646
910
|
const [, varName, varValue] = varMatch;
|
|
647
|
-
//
|
|
648
|
-
const processedValue =
|
|
911
|
+
// 处理变量值中的数学表达式和颜色转换
|
|
912
|
+
const processedValue = processCSSValue(
|
|
649
913
|
replaceVariableUsesInValue(varValue.trim(), {
|
|
650
914
|
...globalVariables,
|
|
651
915
|
...(currentSelector ? selectorVariables.get(currentSelector) || {} : {})
|
|
@@ -764,11 +1028,11 @@
|
|
|
764
1028
|
if (!trimmed.includes('{') && !trimmed.includes('}') && trimmed.includes(':')) {
|
|
765
1029
|
if (stack.length > 0) {
|
|
766
1030
|
const currentRule = stack[stack.length - 1];
|
|
767
|
-
// 处理属性值中的
|
|
1031
|
+
// 处理属性值中的math()函数和颜色转换
|
|
768
1032
|
const parsed = parseSingleLineCSS(trimmed);
|
|
769
1033
|
parsed.forEach(obj => {
|
|
770
1034
|
const key = Object.keys(obj)[0];
|
|
771
|
-
const value =
|
|
1035
|
+
const value = processCSSValue(obj[key], config);
|
|
772
1036
|
currentRule.properties.push(`${key}: ${value}`);
|
|
773
1037
|
});
|
|
774
1038
|
}
|
|
@@ -821,11 +1085,11 @@
|
|
|
821
1085
|
if (rule.properties.length > 0) {
|
|
822
1086
|
result += (isAt ? "" : fullSelector) + ' {\n';
|
|
823
1087
|
for (const prop of rule.properties) {
|
|
824
|
-
// 再次处理属性值(确保
|
|
1088
|
+
// 再次处理属性值(确保math()函数和颜色被转换)
|
|
825
1089
|
const parsed = parseSingleLineCSS(prop);
|
|
826
1090
|
parsed.forEach(obj => {
|
|
827
1091
|
const key = Object.keys(obj)[0];
|
|
828
|
-
const value =
|
|
1092
|
+
const value = processCSSValue(obj[key], config);
|
|
829
1093
|
result += (isParentAt ? ' ' : '') + ` ${key}: ${value};\n`;
|
|
830
1094
|
});
|
|
831
1095
|
}
|
|
@@ -870,10 +1134,8 @@
|
|
|
870
1134
|
return `var(--${varName})`;
|
|
871
1135
|
});
|
|
872
1136
|
|
|
873
|
-
// 最后处理所有的LAB
|
|
874
|
-
|
|
875
|
-
result = convertAllLabLchColors(result, config);
|
|
876
|
-
}
|
|
1137
|
+
// 最后处理所有的LAB、LCH颜色和math()函数
|
|
1138
|
+
result = processCSSValue(result, config);
|
|
877
1139
|
|
|
878
1140
|
return result;
|
|
879
1141
|
}
|
|
@@ -886,7 +1148,7 @@
|
|
|
886
1148
|
|
|
887
1149
|
const declarations = Object.entries(variables)
|
|
888
1150
|
.map(([name, value]) => {
|
|
889
|
-
const processedValue =
|
|
1151
|
+
const processedValue = processCSSValue(
|
|
890
1152
|
replaceVariableUsesInValue(value, variables),
|
|
891
1153
|
config
|
|
892
1154
|
);
|
|
@@ -922,12 +1184,8 @@
|
|
|
922
1184
|
currentSelector = null;
|
|
923
1185
|
}
|
|
924
1186
|
|
|
925
|
-
//
|
|
926
|
-
|
|
927
|
-
result += convertAllLabLchColors(line, config) + '\n';
|
|
928
|
-
} else {
|
|
929
|
-
result += line + '\n';
|
|
930
|
-
}
|
|
1187
|
+
// 使用全局处理函数处理所有math()和颜色
|
|
1188
|
+
result += processCSSValue(line, config) + '\n';
|
|
931
1189
|
}
|
|
932
1190
|
|
|
933
1191
|
return result.trim();
|
|
@@ -1024,7 +1282,7 @@
|
|
|
1024
1282
|
convert,
|
|
1025
1283
|
apply,
|
|
1026
1284
|
config,
|
|
1027
|
-
version: '1.
|
|
1285
|
+
version: '1.9.0',
|
|
1028
1286
|
|
|
1029
1287
|
// 检测P3支持
|
|
1030
1288
|
supportsP3: detectP3Support(),
|
|
@@ -1032,6 +1290,58 @@
|
|
|
1032
1290
|
// 重新检测P3支持(如果配置变化)
|
|
1033
1291
|
detectP3Support: detectP3Support,
|
|
1034
1292
|
|
|
1293
|
+
// 数学计算工具方法
|
|
1294
|
+
math: {
|
|
1295
|
+
/**
|
|
1296
|
+
* 计算数学表达式
|
|
1297
|
+
* @param {string} expression - 数学表达式
|
|
1298
|
+
* @returns {string} 计算结果
|
|
1299
|
+
*/
|
|
1300
|
+
evaluate: function(expression) {
|
|
1301
|
+
return evaluateMathExpression(expression, defaultConfig);
|
|
1302
|
+
},
|
|
1303
|
+
|
|
1304
|
+
/**
|
|
1305
|
+
* 解析带单位的数值
|
|
1306
|
+
* @param {string} value - 带单位的字符串
|
|
1307
|
+
* @returns {Object} {value: number, unit: string}
|
|
1308
|
+
*/
|
|
1309
|
+
parseUnit: parseValueWithUnit,
|
|
1310
|
+
|
|
1311
|
+
/**
|
|
1312
|
+
* 四舍五入数字
|
|
1313
|
+
* @param {number} num - 要四舍五入的数字
|
|
1314
|
+
* @param {number} precision - 精度
|
|
1315
|
+
* @returns {string} 四舍五入后的数字字符串
|
|
1316
|
+
*/
|
|
1317
|
+
round: roundNumber,
|
|
1318
|
+
|
|
1319
|
+
/**
|
|
1320
|
+
* 测试数学表达式
|
|
1321
|
+
* @param {string} expression - 要测试的表达式
|
|
1322
|
+
* @param {Object} testConfig - 测试配置
|
|
1323
|
+
* @returns {Object} 测试结果
|
|
1324
|
+
*/
|
|
1325
|
+
test: function(expression, testConfig = {}) {
|
|
1326
|
+
const config = { ...defaultConfig, ...testConfig };
|
|
1327
|
+
try {
|
|
1328
|
+
const result = evaluateMathExpression(expression, config);
|
|
1329
|
+
return {
|
|
1330
|
+
success: true,
|
|
1331
|
+
expression,
|
|
1332
|
+
result,
|
|
1333
|
+
parsed: parseValueWithUnit(result.replace(/^calc\(|\)$/g, ''))
|
|
1334
|
+
};
|
|
1335
|
+
} catch (error) {
|
|
1336
|
+
return {
|
|
1337
|
+
success: false,
|
|
1338
|
+
expression,
|
|
1339
|
+
error: error.message
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
},
|
|
1344
|
+
|
|
1035
1345
|
// 颜色转换工具方法
|
|
1036
1346
|
colorUtils: {
|
|
1037
1347
|
labToRGB: preciseLabToRGB,
|
|
@@ -1143,6 +1453,66 @@
|
|
|
1143
1453
|
}
|
|
1144
1454
|
}
|
|
1145
1455
|
};
|
|
1456
|
+
|
|
1457
|
+
|
|
1458
|
+
// 创建一个可调用的主函数
|
|
1459
|
+
const styimat = function(...args) {
|
|
1460
|
+
// 检查是否是模板字符串调用(标签函数)
|
|
1461
|
+
if (args.length > 1 || (args[0] && args[0].raw)) {
|
|
1462
|
+
// 处理模板字符串
|
|
1463
|
+
return handleTemplateTag(...args);
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
// 获取第一个参数
|
|
1467
|
+
const firstArg = args[0];
|
|
1468
|
+
|
|
1469
|
+
// 如果传入CSS文本,则编译并返回结果
|
|
1470
|
+
if (typeof firstArg === 'string') {
|
|
1471
|
+
return convert(firstArg, { ...defaultConfig, ...args[1] });
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
// 如果传入配置对象,则应用配置
|
|
1475
|
+
if (typeof firstArg === 'object' && firstArg !== null) {
|
|
1476
|
+
defaultConfig = { ...defaultConfig, ...firstArg };
|
|
1477
|
+
return styimat;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
// 如果没有参数,执行自动处理
|
|
1481
|
+
if (args.length === 0) {
|
|
1482
|
+
return apply();
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
return styimat;
|
|
1486
|
+
};
|
|
1487
|
+
|
|
1488
|
+
// 处理模板字符串的函数
|
|
1489
|
+
function handleTemplateTag(strings, ...values) {
|
|
1490
|
+
// 拼接模板字符串
|
|
1491
|
+
let cssText = strings[0];
|
|
1492
|
+
|
|
1493
|
+
for (let i = 0; i < values.length; i++) {
|
|
1494
|
+
// 处理插值(支持字符串、数字、函数等)
|
|
1495
|
+
const value = values[i];
|
|
1496
|
+
let result = '';
|
|
1497
|
+
|
|
1498
|
+
if (typeof value === 'function') {
|
|
1499
|
+
result = value();
|
|
1500
|
+
} else if (Array.isArray(value)) {
|
|
1501
|
+
result = value.join(' ');
|
|
1502
|
+
} else {
|
|
1503
|
+
result = String(value != null ? value : '');
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
cssText += result + strings[i + 1];
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
// 使用convert函数处理
|
|
1510
|
+
return convert(cssText, defaultConfig);
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
// 将API的所有方法复制到主函数上
|
|
1514
|
+
Object.assign(styimat, api);
|
|
1515
|
+
Object.setPrototypeOf(styimat, Function.prototype);
|
|
1146
1516
|
|
|
1147
1517
|
// 自动初始化
|
|
1148
1518
|
if (typeof window !== 'undefined') {
|
|
@@ -1152,12 +1522,12 @@
|
|
|
1152
1522
|
const element = this;
|
|
1153
1523
|
return new Proxy({}, {
|
|
1154
1524
|
get(target, prop) {
|
|
1155
|
-
const varName = prop.startsWith('
|
|
1525
|
+
const varName = prop.startsWith('--') ? prop : `--${prop}`;
|
|
1156
1526
|
return element.style.getPropertyValue(varName);
|
|
1157
1527
|
},
|
|
1158
1528
|
|
|
1159
1529
|
set(target, prop, value) {
|
|
1160
|
-
const varName = prop.startsWith('
|
|
1530
|
+
const varName = prop.startsWith('--') ? prop : `--${prop}`;
|
|
1161
1531
|
element.style.setProperty(varName, value);
|
|
1162
1532
|
return true;
|
|
1163
1533
|
}
|
|
@@ -1166,5 +1536,5 @@
|
|
|
1166
1536
|
});
|
|
1167
1537
|
}
|
|
1168
1538
|
|
|
1169
|
-
return
|
|
1539
|
+
return styimat;
|
|
1170
1540
|
}));
|
package/styimat.min.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* MIT License
|
|
3
|
+
* Copyright (c) 2025 王小玗
|
|
4
|
+
*/
|
|
1
5
|
/**
|
|
2
6
|
* CSS 变量预处理库 - 增强版
|
|
3
7
|
* 支持 CSS 变量预处理、嵌套选择器和嵌套变量
|
|
4
8
|
* 支持 Lab 和 LCH 颜色空间转换为 RGB(CSS标准格式)
|
|
5
9
|
* 支持 lab# 和 lch# 十六进制语法
|
|
6
10
|
* 支持 Display P3 广色域显示器
|
|
11
|
+
* 增强 math() 函数,支持复杂数学计算
|
|
7
12
|
*/
|
|
8
13
|
(function(root,factory){if(typeof define==="function"&&define.amd){
|
|
9
14
|
// AMD 支持 (RequireJS)
|
|
@@ -13,9 +18,8 @@ module.exports=factory()}else{
|
|
|
13
18
|
// 浏览器全局变量
|
|
14
19
|
root.styimat=factory()}})(typeof self!=="undefined"?self:this,function(){
|
|
15
20
|
// 默认配置
|
|
16
|
-
let defaultConfig={rootSelector:":root",variablePrefix:"--",preserveOriginal:false,indentSize:2,enableNesting:true,autoProcessStyleTags:true,styleTagAttribute:"e",convertLabToRGB:true,//
|
|
17
|
-
|
|
18
|
-
enableP3:true};
|
|
21
|
+
let defaultConfig={rootSelector:":root",variablePrefix:"--",preserveOriginal:false,indentSize:2,enableNesting:true,autoProcessStyleTags:true,styleTagAttribute:"e",convertLabToRGB:true,convertLchToRGB:true,enableP3:true,enableMath:true,// 启用math()函数增强
|
|
22
|
+
mathPrecision:6};
|
|
19
23
|
// 全局P3支持检测结果
|
|
20
24
|
let p3Supported=null;
|
|
21
25
|
/**
|
|
@@ -68,6 +72,108 @@ result.push({[property]:value})}return result}
|
|
|
68
72
|
if((char==='"'||char==="'")&&!inQuotes){inQuotes=true;quoteChar=char}else if(char===quoteChar&&inQuotes){inQuotes=false;quoteChar=""}
|
|
69
73
|
// 如果找到冒号且不在引号内,返回位置
|
|
70
74
|
if(char===":"&&!inQuotes){return i}}return-1}
|
|
75
|
+
/**
|
|
76
|
+
* 增强的数学表达式解析和计算
|
|
77
|
+
* @param {string} expression - 数学表达式
|
|
78
|
+
* @param {Object} config - 配置对象
|
|
79
|
+
* @returns {string} 计算结果
|
|
80
|
+
*/function evaluateMathExpression(expression,config){
|
|
81
|
+
// 如果禁用math()增强,则返回原始表达式
|
|
82
|
+
if(!config.enableMath){return`math(${expression})`}try{
|
|
83
|
+
// 清理表达式:移除空白字符
|
|
84
|
+
let cleanExpr=expression.replace(/\s+/g,"");
|
|
85
|
+
// 解析数学表达式
|
|
86
|
+
const result=parseMathExpression(cleanExpr,config);
|
|
87
|
+
// 如果结果包含单位,保留原始格式
|
|
88
|
+
if(hasUnits(cleanExpr)){
|
|
89
|
+
// 处理带单位的表达式
|
|
90
|
+
return processUnitExpression(cleanExpr,result)}else{
|
|
91
|
+
// 纯数字表达式,直接计算结果
|
|
92
|
+
return roundNumber(result,config.mathPrecision)}}catch(error){console.warn("math()表达式解析失败:",expression,error);return`math(${expression})`}}
|
|
93
|
+
/**
|
|
94
|
+
* 解析数学表达式
|
|
95
|
+
* @param {string} expr - 清理后的表达式
|
|
96
|
+
* @param {Object} config - 配置对象
|
|
97
|
+
* @returns {number} 计算结果
|
|
98
|
+
*/function parseMathExpression(expr,config){
|
|
99
|
+
// 处理括号
|
|
100
|
+
while(expr.includes("(")&&expr.includes(")")){const start=expr.lastIndexOf("(");const end=expr.indexOf(")",start);if(end===-1)break;const inner=expr.substring(start+1,end);const innerResult=parseMathExpression(inner,config);expr=expr.substring(0,start)+innerResult+expr.substring(end+1)}
|
|
101
|
+
// 现在expr应该没有括号了
|
|
102
|
+
return evaluateSimpleExpression(expr,config)}
|
|
103
|
+
/**
|
|
104
|
+
* 评估简单表达式(无括号)
|
|
105
|
+
* @param {string} expr - 简单表达式
|
|
106
|
+
* @param {Object} config - 配置对象
|
|
107
|
+
* @returns {number} 计算结果
|
|
108
|
+
*/function evaluateSimpleExpression(expr,config){
|
|
109
|
+
// 处理操作符优先级:乘除优先于加减
|
|
110
|
+
const operators=[{regex:/([\d.]+(?:[a-zA-Z%]+)?)\*([\d.]+(?:[a-zA-Z%]+)?)/,handler:multiply},{regex:/([\d.]+(?:[a-zA-Z%]+)?)\/([\d.]+(?:[a-zA-Z%]+)?)/,handler:divide},{regex:/([\d.]+(?:[a-zA-Z%]+)?)\+([\d.]+(?:[a-zA-Z%]+)?)/,handler:add},{regex:/([\d.]+(?:[a-zA-Z%]+)?)-([\d.]+(?:[a-zA-Z%]+)?)/,handler:subtract}];let lastExpr=expr;
|
|
111
|
+
// 按照优先级处理操作符
|
|
112
|
+
for(const op of operators){let match;while((match=expr.match(op.regex))!==null){const left=parseValueWithUnit(match[1]);const right=parseValueWithUnit(match[2]);const result=op.handler(left,right);
|
|
113
|
+
// 替换匹配的部分
|
|
114
|
+
expr=expr.substring(0,match.index)+result.value+expr.substring(match.index+match[0].length)}}
|
|
115
|
+
// 如果表达式无法进一步简化,尝试解析为数字
|
|
116
|
+
if(expr!==lastExpr){return evaluateSimpleExpression(expr,config)}
|
|
117
|
+
// 解析最终结果
|
|
118
|
+
const parsed=parseValueWithUnit(expr);return parsed.value}
|
|
119
|
+
/**
|
|
120
|
+
* 解析带单位的数值
|
|
121
|
+
* @param {string} str - 字符串值
|
|
122
|
+
* @returns {Object} {value: number, unit: string}
|
|
123
|
+
*/function parseValueWithUnit(str){
|
|
124
|
+
// 匹配数值和单位
|
|
125
|
+
const match=str.match(/^([\d.]+)([a-zA-Z%]*)$/);if(!match){throw new Error(`无法解析值: ${str}`)}const value=parseFloat(match[1]);const unit=match[2]||"";return{value:value,unit:unit}}
|
|
126
|
+
/**
|
|
127
|
+
* 检查表达式是否包含单位
|
|
128
|
+
* @param {string} expr - 表达式
|
|
129
|
+
* @returns {boolean} 是否包含单位
|
|
130
|
+
*/function hasUnits(expr){return/[a-zA-Z%]/.test(expr)}
|
|
131
|
+
/**
|
|
132
|
+
* 处理带单位的表达式
|
|
133
|
+
* @param {string} originalExpr - 原始表达式
|
|
134
|
+
* @param {number} result - 计算结果
|
|
135
|
+
* @returns {string} 处理后的表达式
|
|
136
|
+
*/function processUnitExpression(originalExpr,result){
|
|
137
|
+
// 提取原始表达式中的单位
|
|
138
|
+
const unitMatch=originalExpr.match(/([a-zA-Z%]+)(?!.*[a-zA-Z%])/);if(unitMatch){return result+unitMatch[1]}
|
|
139
|
+
// 如果没有明确单位,检查是否为百分比
|
|
140
|
+
if(originalExpr.includes("%")){return result+"%"}
|
|
141
|
+
// 默认为像素
|
|
142
|
+
return result+"px"}
|
|
143
|
+
// 数学运算函数
|
|
144
|
+
function multiply(a,b){if(a.unit===b.unit||!a.unit&&!b.unit){return{value:a.value*b.value,unit:a.unit||b.unit}}
|
|
145
|
+
// 单位不匹配,返回原始表达式
|
|
146
|
+
return{value:`${a.value}${a.unit}*${b.value}${b.unit}`,unit:""}}function divide(a,b){if(b.value===0){throw new Error("除以零")}if(a.unit&&!b.unit){
|
|
147
|
+
// 如 100px / 2
|
|
148
|
+
return{value:a.value/b.value,unit:a.unit}}else if(a.unit===b.unit){
|
|
149
|
+
// 如 100px / 2px
|
|
150
|
+
return{value:a.value/b.value,unit:""}}
|
|
151
|
+
// 单位不匹配,返回原始表达式
|
|
152
|
+
return{value:`${a.value}${a.unit}/${b.value}${b.unit}`,unit:""}}function add(a,b){if(a.unit===b.unit){return{value:a.value+b.value,unit:a.unit}}
|
|
153
|
+
// 单位不匹配,返回原始表达式
|
|
154
|
+
return{value:`${a.value}${a.unit}+${b.value}${b.unit}`,unit:""}}function subtract(a,b){if(a.unit===b.unit){return{value:a.value-b.value,unit:a.unit}}
|
|
155
|
+
// 单位不匹配,返回原始表达式
|
|
156
|
+
return{value:`${a.value}${a.unit}-${b.value}${b.unit}`,unit:""}}
|
|
157
|
+
/**
|
|
158
|
+
* 四舍五入到指定精度
|
|
159
|
+
* @param {number} num - 要四舍五入的数字
|
|
160
|
+
* @param {number} precision - 精度
|
|
161
|
+
* @returns {string} 四舍五入后的数字字符串
|
|
162
|
+
*/function roundNumber(num,precision=6){const factor=Math.pow(10,precision);const rounded=Math.round(num*factor)/factor;
|
|
163
|
+
// 移除不必要的尾随零
|
|
164
|
+
const str=rounded.toString();if(str.includes(".")){return str.replace(/(\.\d*?)0+$/,"$1").replace(/\.$/,"")}return str}
|
|
165
|
+
/**
|
|
166
|
+
* 处理所有的math()函数
|
|
167
|
+
* @param {string} cssValue - CSS属性值
|
|
168
|
+
* @param {Object} config - 配置对象
|
|
169
|
+
* @returns {string} 转换后的CSS值
|
|
170
|
+
*/function processMathFunctions(cssValue,config){if(!config.enableMath){return cssValue}let result=cssValue;
|
|
171
|
+
// 匹配math()函数
|
|
172
|
+
const mathRegex=/math\(([^)]+)\)/gi;
|
|
173
|
+
// 递归处理嵌套的math()函数
|
|
174
|
+
const processMath=str=>str.replace(mathRegex,(match,expression)=>evaluateMathExpression(expression,config));
|
|
175
|
+
// 递归处理,直到没有更多math()函数
|
|
176
|
+
let lastResult;do{lastResult=result;result=processMath(result)}while(result!==lastResult&&result.includes("math("));return result}
|
|
71
177
|
/**
|
|
72
178
|
* 解析并转换所有的 Lab 和 LCH 颜色(全局一次性处理)
|
|
73
179
|
* @param {string} cssValue - CSS属性值
|
|
@@ -218,20 +324,21 @@ const rgb=preciseLabToRGB(L,a,b);if(alpha!==null){return`rgba(${rgb.r}, ${rgb.g}
|
|
|
218
324
|
// 使用P3
|
|
219
325
|
const p3=labToP3(L,a,b);if(alpha!==null){return`color(display-p3 ${p3.r.toFixed(4)} ${p3.g.toFixed(4)} ${p3.b.toFixed(4)} / ${alpha})`}return`color(display-p3 ${p3.r.toFixed(4)} ${p3.g.toFixed(4)} ${p3.b.toFixed(4)})`}}
|
|
220
326
|
/**
|
|
221
|
-
* 处理CSS值,根据配置转换LAB
|
|
327
|
+
* 处理CSS值,根据配置转换LAB、LCH颜色和math()函数
|
|
222
328
|
* @param {string} value - CSS属性值
|
|
223
329
|
* @param {Object} config - 配置对象
|
|
224
330
|
* @returns {string} 处理后的值
|
|
225
|
-
*/function processCSSValue(value,config){
|
|
226
|
-
//
|
|
227
|
-
|
|
331
|
+
*/function processCSSValue(value,config){let result=value;
|
|
332
|
+
// 1. 首先处理math()函数
|
|
333
|
+
if(config.enableMath){result=processMathFunctions(result,config)}
|
|
334
|
+
// 2. 然后处理LAB和LCH颜色
|
|
335
|
+
if(config.convertLabToRGB||config.convertLchToRGB){result=convertAllLabLchColors(result,config)}return result}
|
|
228
336
|
// 私有方法:提取变量定义并移除(支持嵌套作用域)
|
|
229
|
-
function extractVariablesAndCSS(cssText,config){const lines=cssText.split("\n");const globalVariables={};const selectorVariables=new Map
|
|
230
|
-
let cssWithoutVars="";let currentSelector=null;let inSelectorBlock=false;let currentIndent=0;for(let line of lines){const trimmed=line.trim();
|
|
337
|
+
function extractVariablesAndCSS(cssText,config){const lines=cssText.split("\n");const globalVariables={};const selectorVariables=new Map;let cssWithoutVars="";let currentSelector=null;let inSelectorBlock=false;let currentIndent=0;for(let line of lines){const trimmed=line.trim();
|
|
231
338
|
// 检查是否是变量定义
|
|
232
339
|
const varMatch=trimmed.match(/^\$([a-zA-Z0-9_-]+)\s*:\s*(.+?);?$/);if(varMatch){const[,varName,varValue]=varMatch;
|
|
233
|
-
//
|
|
234
|
-
const processedValue=
|
|
340
|
+
// 处理变量值中的数学表达式和颜色转换
|
|
341
|
+
const processedValue=processCSSValue(replaceVariableUsesInValue(varValue.trim(),{...globalVariables,...currentSelector?selectorVariables.get(currentSelector)||{}:{}}),config);if(currentSelector){
|
|
235
342
|
// 选择器内部的变量
|
|
236
343
|
if(!selectorVariables.has(currentSelector)){selectorVariables.set(currentSelector,{})}selectorVariables.get(currentSelector)[varName]=processedValue}else{
|
|
237
344
|
// 全局变量(:root 中)
|
|
@@ -263,8 +370,8 @@ const rule={selector:selector,properties:[],children:[],indentLevel:indentLevel}
|
|
|
263
370
|
stack.push(rule);continue}
|
|
264
371
|
// 处理属性行(不包含 { 或 } 的行)
|
|
265
372
|
if(!trimmed.includes("{")&&!trimmed.includes("}")&&trimmed.includes(":")){if(stack.length>0){const currentRule=stack[stack.length-1];
|
|
266
|
-
// 处理属性值中的
|
|
267
|
-
const parsed=parseSingleLineCSS(trimmed);parsed.forEach(obj=>{const key=Object.keys(obj)[0];const value=
|
|
373
|
+
// 处理属性值中的math()函数和颜色转换
|
|
374
|
+
const parsed=parseSingleLineCSS(trimmed);parsed.forEach(obj=>{const key=Object.keys(obj)[0];const value=processCSSValue(obj[key],config);currentRule.properties.push(`${key}: ${value}`)})}continue}}
|
|
268
375
|
// 处理栈中剩余规则
|
|
269
376
|
while(stack.length>0){const rule=stack.pop();if(stack.length===0){rootRules.push(rule)}else{const parent=stack[stack.length-1];if(!parent.children)parent.children=[];parent.children.push(rule)}}
|
|
270
377
|
// 将规则树转换为CSS字符串
|
|
@@ -277,8 +384,8 @@ const isAt=rule.selector.startsWith("@");let fullSelector=(isParentAt?" ":"")+r
|
|
|
277
384
|
if(fullSelector.includes("&")){fullSelector=fullSelector.replace(/&/g,parentSelector)}else if(fullSelector.trim().startsWith(":")){fullSelector=parentSelector+fullSelector}else{fullSelector=parentSelector+(isParentAt?"":" ")+fullSelector}}
|
|
278
385
|
// 如果有属性,生成规则块
|
|
279
386
|
if(rule.properties.length>0){result+=(isAt?"":fullSelector)+" {\n";for(const prop of rule.properties){
|
|
280
|
-
// 再次处理属性值(确保
|
|
281
|
-
const parsed=parseSingleLineCSS(prop);parsed.forEach(obj=>{const key=Object.keys(obj)[0];const value=
|
|
387
|
+
// 再次处理属性值(确保math()函数和颜色被转换)
|
|
388
|
+
const parsed=parseSingleLineCSS(prop);parsed.forEach(obj=>{const key=Object.keys(obj)[0];const value=processCSSValue(obj[key],config);result+=(isParentAt?" ":"")+` ${key}: ${value};\n`})}result+=isParentAt?" }\n":"}\n\n"}
|
|
282
389
|
// 递归处理子规则
|
|
283
390
|
if(rule.children&&rule.children.length>0){result+=convertRulesToCSS(rule.children,config,fullSelector)}if(isParentAt){result+="}\n\n"}}return result.trim()+(isParentAt?"\n\n":"")}
|
|
284
391
|
// 替换变量值中的变量引用
|
|
@@ -289,16 +396,16 @@ function replaceVariableUses(cssText,globalVariables,selectorVariables,config){l
|
|
|
289
396
|
for(const[varName,varValue]of Object.entries(globalVariables)){const varRegex=new RegExp(`\\$${varName}(?![a-zA-Z0-9_-])`,"g");result=result.replace(varRegex,`var(--${varName})`)}
|
|
290
397
|
// 然后处理选择器特定的变量
|
|
291
398
|
result=result.replace(/\$([a-zA-Z0-9_-]+)/g,(match,varName)=>`var(--${varName})`);
|
|
292
|
-
// 最后处理所有的LAB
|
|
293
|
-
|
|
399
|
+
// 最后处理所有的LAB、LCH颜色和math()函数
|
|
400
|
+
result=processCSSValue(result,config);return result}
|
|
294
401
|
// 生成根规则
|
|
295
|
-
function generateRootRule(variables,config){if(Object.keys(variables).length===0){return""}const declarations=Object.entries(variables).map(([name,value])=>{const processedValue=
|
|
402
|
+
function generateRootRule(variables,config){if(Object.keys(variables).length===0){return""}const declarations=Object.entries(variables).map(([name,value])=>{const processedValue=processCSSValue(replaceVariableUsesInValue(value,variables),config);return` --${name}: ${processedValue};`}).join("\n");return`${config.rootSelector} {\n${declarations}\n}\n\n`}
|
|
296
403
|
// 处理选择器内部的变量
|
|
297
404
|
function injectSelectorVariables(cssText,selectorVariables,config){let result="";const lines=cssText.split("\n");let currentSelector=null;for(let line of lines){const trimmed=line.trim();if(trimmed.endsWith("{")){currentSelector=trimmed.slice(0,-1).trim()}if(trimmed==="}"&¤tSelector){
|
|
298
405
|
// 在选择器结束前插入变量声明
|
|
299
406
|
if(selectorVariables.has(currentSelector)){const vars=selectorVariables.get(currentSelector);const indent=line.match(/^(\s*)/)[0];for(const[varName,varValue]of Object.entries(vars)){result+=indent+" --"+varName+": "+varValue+";\n"}}currentSelector=null}
|
|
300
|
-
//
|
|
301
|
-
|
|
407
|
+
// 使用全局处理函数处理所有math()和颜色
|
|
408
|
+
result+=processCSSValue(line,config)+"\n"}return result.trim()}
|
|
302
409
|
// 主转换函数
|
|
303
410
|
function convert(cssText,customConfig={}){const config={...defaultConfig,...customConfig};
|
|
304
411
|
// 1. 提取变量定义(区分全局和选择器局部)
|
|
@@ -324,11 +431,39 @@ if(!config.preserveOriginal){styleTag.remove()}else{styleTag.style.display="none
|
|
|
324
431
|
// 初始化自动处理
|
|
325
432
|
function apply(cssText,customConfig={}){const config={...defaultConfig,...customConfig};if(cssText){const converted=convert(cssText,config);const styleEl=document.createElement("style");styleEl.textContent=converted;document.head.appendChild(styleEl);return styleEl}else{if(document.readyState==="loading"){document.addEventListener("DOMContentLoaded",()=>{autoProcessStyleTags(config)})}else{autoProcessStyleTags(config)}}}
|
|
326
433
|
// 返回公共 API
|
|
327
|
-
const api={convert:convert,apply:apply,config:config,version:"1.
|
|
434
|
+
const api={convert:convert,apply:apply,config:config,version:"1.9.0",
|
|
328
435
|
// 检测P3支持
|
|
329
436
|
supportsP3:detectP3Support(),
|
|
330
437
|
// 重新检测P3支持(如果配置变化)
|
|
331
438
|
detectP3Support:detectP3Support,
|
|
439
|
+
// 数学计算工具方法
|
|
440
|
+
math:{
|
|
441
|
+
/**
|
|
442
|
+
* 计算数学表达式
|
|
443
|
+
* @param {string} expression - 数学表达式
|
|
444
|
+
* @returns {string} 计算结果
|
|
445
|
+
*/
|
|
446
|
+
evaluate:function(expression){return evaluateMathExpression(expression,defaultConfig)},
|
|
447
|
+
/**
|
|
448
|
+
* 解析带单位的数值
|
|
449
|
+
* @param {string} value - 带单位的字符串
|
|
450
|
+
* @returns {Object} {value: number, unit: string}
|
|
451
|
+
*/
|
|
452
|
+
parseUnit:parseValueWithUnit,
|
|
453
|
+
/**
|
|
454
|
+
* 四舍五入数字
|
|
455
|
+
* @param {number} num - 要四舍五入的数字
|
|
456
|
+
* @param {number} precision - 精度
|
|
457
|
+
* @returns {string} 四舍五入后的数字字符串
|
|
458
|
+
*/
|
|
459
|
+
round:roundNumber,
|
|
460
|
+
/**
|
|
461
|
+
* 测试数学表达式
|
|
462
|
+
* @param {string} expression - 要测试的表达式
|
|
463
|
+
* @param {Object} testConfig - 测试配置
|
|
464
|
+
* @returns {Object} 测试结果
|
|
465
|
+
*/
|
|
466
|
+
test:function(expression,testConfig={}){const config={...defaultConfig,...testConfig};try{const result=evaluateMathExpression(expression,config);return{success:true,expression:expression,result:result,parsed:parseValueWithUnit(result.replace(/^calc\(|\)$/g,""))}}catch(error){return{success:false,expression:expression,error:error.message}}}},
|
|
332
467
|
// 颜色转换工具方法
|
|
333
468
|
colorUtils:{labToRGB:preciseLabToRGB,lchToLab:lchToLab,lchToRGB:function(L,C,H){const lab=lchToLab(L,C,H);return preciseLabToRGB(lab.L,lab.a,lab.b)},labToP3:labToP3,lchToP3:function(L,C,H){const lab=lchToLab(L,C,H);return labToP3(lab.L,lab.a,lab.b)},parseHexLab:function(hexString){const match=hexString.match(/lab#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i);if(!match)return null;const L_hex=match[1];const A_hex=match[2];const B_hex=match[3];const L=parseInt(L_hex,16)/255*100;const A=(parseInt(A_hex,16)-128)*1.5;const B=(parseInt(B_hex,16)-128)*1.5;return preciseLabToRGB(L,A,B)},parseHexLch:function(hexString){const match=hexString.match(/lch#([0-9a-f]{2})([0-9a-f]{2})(\d{1,3})/i);if(!match)return null;const L_hex=match[1];const C_hex=match[2];const H_dec=match[3];const L=parseInt(L_hex,16)/255*100;const C=parseInt(C_hex,16)/255*150;const H=parseInt(H_dec)/100*360;const lab=lchToLab(L,C,H);return preciseLabToRGB(lab.L,lab.a,lab.b)},
|
|
334
469
|
/**
|
|
@@ -351,5 +486,29 @@ parseColor:function(colorString){try{
|
|
|
351
486
|
const labMatch=colorString.match(/lab\(\s*([\d.]+)(%?)\s+([\d.-]+)\s+([\d.-]+)(?:\s*\/\s*([\d.%]+))?\s*\)/i);if(labMatch){let L=parseFloat(labMatch[1]);const A=parseFloat(labMatch[3]);const B=parseFloat(labMatch[4]);const alpha=labMatch[5]?labMatch[5].includes("%")?parseFloat(labMatch[5])/100:parseFloat(labMatch[5]):null;const colorStr=generateColorString(L,A,B,defaultConfig,alpha);return{L:L,A:A,B:B,alpha:alpha,rgb:preciseLabToRGB(L,A,B),p3:labToP3(L,A,B),colorString:colorStr}}
|
|
352
487
|
// 尝试解析lch()函数格式
|
|
353
488
|
const lchMatch=colorString.match(/lch\(\s*([\d.]+)(%?)\s+([\d.]+)\s+([\d.]+)(deg)?(?:\s*\/\s*([\d.%]+))?\s*\)/i);if(lchMatch){let L=parseFloat(lchMatch[1]);const C=parseFloat(lchMatch[3]);let H=parseFloat(lchMatch[4]);const alpha=lchMatch[6]?lchMatch[6].includes("%")?parseFloat(lchMatch[6])/100:parseFloat(lchMatch[6]):null;const lab=lchToLab(L,C,H);const colorStr=generateColorString(lab.L,lab.a,lab.b,defaultConfig,alpha);return{L:L,C:C,H:H,alpha:alpha,lab:lab,rgb:preciseLabToRGB(lab.L,lab.a,lab.b),p3:labToP3(lab.L,lab.a,lab.b),colorString:colorStr}}return null}catch(error){console.warn("无法解析颜色:",colorString,error);return null}}}};
|
|
489
|
+
// 创建一个可调用的主函数
|
|
490
|
+
const styimat=function(...args){
|
|
491
|
+
// 检查是否是模板字符串调用(标签函数)
|
|
492
|
+
if(args.length>1||args[0]&&args[0].raw){
|
|
493
|
+
// 处理模板字符串
|
|
494
|
+
return handleTemplateTag(...args)}
|
|
495
|
+
// 获取第一个参数
|
|
496
|
+
const firstArg=args[0];
|
|
497
|
+
// 如果传入CSS文本,则编译并返回结果
|
|
498
|
+
if(typeof firstArg==="string"){return convert(firstArg,{...defaultConfig,...args[1]})}
|
|
499
|
+
// 如果传入配置对象,则应用配置
|
|
500
|
+
if(typeof firstArg==="object"&&firstArg!==null){defaultConfig={...defaultConfig,...firstArg};return styimat}
|
|
501
|
+
// 如果没有参数,执行自动处理
|
|
502
|
+
if(args.length===0){return apply()}return styimat};
|
|
503
|
+
// 处理模板字符串的函数
|
|
504
|
+
function handleTemplateTag(strings,...values){
|
|
505
|
+
// 拼接模板字符串
|
|
506
|
+
let cssText=strings[0];for(let i=0;i<values.length;i++){
|
|
507
|
+
// 处理插值(支持字符串、数字、函数等)
|
|
508
|
+
const value=values[i];let result="";if(typeof value==="function"){result=value()}else if(Array.isArray(value)){result=value.join(" ")}else{result=String(value!=null?value:"")}cssText+=result+strings[i+1]}
|
|
509
|
+
// 使用convert函数处理
|
|
510
|
+
return convert(cssText,defaultConfig)}
|
|
511
|
+
// 将API的所有方法复制到主函数上
|
|
512
|
+
Object.assign(styimat,api);Object.setPrototypeOf(styimat,Function.prototype);
|
|
354
513
|
// 自动初始化
|
|
355
|
-
if(typeof window!=="undefined"){apply();Object.defineProperty(window.HTMLElement.prototype,"cssVar",{get(){const element=this;return new Proxy({},{get(target,prop){const varName=prop.startsWith("
|
|
514
|
+
if(typeof window!=="undefined"){apply();Object.defineProperty(window.HTMLElement.prototype,"cssVar",{get(){const element=this;return new Proxy({},{get(target,prop){const varName=prop.startsWith("--")?prop:`--${prop}`;return element.style.getPropertyValue(varName)},set(target,prop,value){const varName=prop.startsWith("--")?prop:`--${prop}`;element.style.setProperty(varName,value);return true}})}})}return styimat});
|