xiangjsoncraft 1.1.2 → 1.2.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 +257 -304
- package/config.json +69 -174
- package/package.json +1 -1
- package/renderJson.js +114 -63
package/README.md
CHANGED
|
@@ -1,355 +1,308 @@
|
|
|
1
1
|
# XiangJsonCraft
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- **简单易用**:仅需一行 API 调用,即可完成整个页面的样式和内容渲染
|
|
17
|
-
- **灵活配置**:通过单一 JSON 文件定义所有样式、文本、HTML 内容,支持按需修改
|
|
18
|
-
- **轻量级无依赖**:原生 JavaScript 开发,无任何第三方依赖,体积小巧,加载速度快
|
|
19
|
-
- **全面的 CSS 支持**:兼容所有 CSS 选择器(类、ID、伪类、伪元素、媒体查询等)
|
|
20
|
-
- **响应式设计友好**:直接通过 JSON 配置媒体查询,轻松实现多屏幕尺寸适配
|
|
21
|
-
- **双内容类型支持**:同时支持纯文本、HTML 片段动态注入,满足不同内容渲染需求
|
|
22
|
-
- **多环境适配**:支持本地模块化引入、CDN 全局调用,适配所有现代浏览器
|
|
23
|
-
- **高容错性**:自动过滤无效配置、空样式,避免单一配置错误导致整体渲染失败
|
|
24
|
-
|
|
25
|
-
## 📦 安装使用
|
|
26
|
-
### 1. npm 安装
|
|
27
|
-
```bash
|
|
28
|
-
# npm
|
|
29
|
-
npm install xiangjsoncraft --save
|
|
30
|
-
|
|
31
|
-
# yarn
|
|
32
|
-
yarn add xiangjsoncraft
|
|
33
|
-
|
|
34
|
-
# pnpm
|
|
35
|
-
pnpm add xiangjsoncraft
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### 2. CDN 在线使用(零安装)
|
|
39
|
-
无需本地安装,一行脚本引入即可全局调用,适合快速原型开发、静态页面使用:
|
|
40
|
-
```html
|
|
41
|
-
<!-- 引入UMD包,自动挂载全局变量 XiangJsonCraft -->
|
|
42
|
-
<script src="https://cdn.jsdelivr.net/npm/xiangjsoncraft@1.1.1/dist/xiangjsoncraft.umd.js"></script>
|
|
43
|
-
<!-- 直接调用核心方法,零配置渲染 -->
|
|
44
|
-
<script>
|
|
45
|
-
XiangJsonCraft.renderJsonStyles();
|
|
46
|
-
</script>
|
|
2
|
+
一款**以JSON解耦网页样式与内容**的轻量级前端工具,无需手写CSS/修改JS,仅通过编辑JSON配置文件即可快速定制网页,实现「HTML搭骨架、JSON定样式填内容」的开发模式,降低页面定制门槛,让非前端开发者也能轻松制作网页。
|
|
3
|
+
|
|
4
|
+
## 核心特色
|
|
5
|
+
✅ **JSON完全解耦**:样式、文本/HTML内容全由JSON配置,HTML仅负责搭建DOM骨架,后期维护只需改JSON
|
|
6
|
+
✅ **双环境兼容**:本地引入/CDN在线引入均支持,**本地config.json永远最高优先级**,CDN提供官方示例配置兜底
|
|
7
|
+
✅ **零门槛上手**:无需复杂配置,3个文件即可实现页面开发,支持驼峰属性自动转CSS标准短横线
|
|
8
|
+
✅ **强容错性**:过滤无效配置、非标准属性,单个配置错误不影响整体渲染,控制台友好日志提示
|
|
9
|
+
✅ **丰富样式支持**:兼容CSS全局样式、hover动效、过渡动画、媒体查询响应式,生成样式自动格式化
|
|
10
|
+
✅ **轻量无依赖**:核心代码仅百行,无第三方依赖,打包后UMD格式体积极小,不占用项目资源
|
|
11
|
+
|
|
12
|
+
## 快速开始
|
|
13
|
+
### 方式1:CDN在线引入(推荐,零文件下载,快速体验/开发)
|
|
14
|
+
仅需2个文件(`index.html` + 自定义`config.json`),一行脚本引入,无需打包/安装依赖。
|
|
15
|
+
#### 项目目录
|
|
47
16
|
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
在项目根目录/HTML 同级目录创建 `config.json`,定义页面的样式、文本及 HTML 内容,支持所有 CSS 选择器和媒体查询:
|
|
52
|
-
```json
|
|
53
|
-
{
|
|
54
|
-
"styles": {
|
|
55
|
-
"*": {
|
|
56
|
-
"margin": "0",
|
|
57
|
-
"padding": "0",
|
|
58
|
-
"boxSizing": "border-box"
|
|
59
|
-
},
|
|
60
|
-
"body": {
|
|
61
|
-
"fontFamily": "Arial, sans-serif",
|
|
62
|
-
"lineHeight": "1.6",
|
|
63
|
-
"color": "#333",
|
|
64
|
-
"backgroundColor": "#f9f9f9",
|
|
65
|
-
"padding": "2rem"
|
|
66
|
-
},
|
|
67
|
-
".header": {
|
|
68
|
-
"backgroundColor": "#2c3e50",
|
|
69
|
-
"color": "white",
|
|
70
|
-
"padding": "1.5rem",
|
|
71
|
-
"textAlign": "center",
|
|
72
|
-
"borderRadius": "8px",
|
|
73
|
-
"marginBottom": "2rem"
|
|
74
|
-
},
|
|
75
|
-
"nav ul": {
|
|
76
|
-
"display": "flex",
|
|
77
|
-
"listStyle": "none",
|
|
78
|
-
"justifyContent": "center",
|
|
79
|
-
"gap": "1.5rem",
|
|
80
|
-
"marginBottom": "2rem"
|
|
81
|
-
},
|
|
82
|
-
"nav a": {
|
|
83
|
-
"color": "#2c3e50",
|
|
84
|
-
"textDecoration": "none",
|
|
85
|
-
"fontSize": "1.1rem"
|
|
86
|
-
},
|
|
87
|
-
"nav a:hover": {
|
|
88
|
-
"color": "#f39c12",
|
|
89
|
-
"textDecoration": "underline"
|
|
90
|
-
},
|
|
91
|
-
".card": {
|
|
92
|
-
"background": "white",
|
|
93
|
-
"padding": "2rem",
|
|
94
|
-
"borderRadius": "8px",
|
|
95
|
-
"boxShadow": "0 2px 8px rgba(0,0,0,0.1)"
|
|
96
|
-
},
|
|
97
|
-
"@media (max-width: 768px)": {
|
|
98
|
-
"body": {
|
|
99
|
-
"padding": "1rem"
|
|
100
|
-
},
|
|
101
|
-
"nav ul": {
|
|
102
|
-
"flexDirection": "column",
|
|
103
|
-
"alignItems": "center",
|
|
104
|
-
"gap": "1rem"
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
"content": {
|
|
109
|
-
".header h1": {
|
|
110
|
-
"value": "XiangJsonCraft 演示页面",
|
|
111
|
-
"isHtml": false
|
|
112
|
-
},
|
|
113
|
-
".card h2": {
|
|
114
|
-
"value": "<span style='color:#2c3e50;'>JSON 配置渲染</span> 就是这么简单",
|
|
115
|
-
"isHtml": true
|
|
116
|
-
},
|
|
117
|
-
".card p": {
|
|
118
|
-
"value": "通过单个 JSON 文件定义所有样式和内容,一行代码完成页面渲染,实现代码与配置的解耦管理。",
|
|
119
|
-
"isHtml": false
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
17
|
+
your-project/
|
|
18
|
+
├─ index.html # 仅写DOM骨架,无手动CSS
|
|
19
|
+
└─ config.json # 你的自定义配置文件(核心,样式+内容全在这里)
|
|
123
20
|
```
|
|
124
|
-
|
|
125
|
-
### 步骤2:创建 HTML 页面
|
|
126
|
-
创建 `index.html`,引入渲染容器并调用核心 API,无需手写任何 CSS 样式:
|
|
21
|
+
#### 1. 编写index.html(DOM骨架,选择器与JSON严格对应)
|
|
127
22
|
```html
|
|
128
23
|
<!DOCTYPE html>
|
|
129
|
-
<html lang="
|
|
24
|
+
<html lang="zh-CN">
|
|
130
25
|
<head>
|
|
131
26
|
<meta charset="UTF-8">
|
|
132
27
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
133
|
-
<title>XiangJsonCraft
|
|
134
|
-
|
|
28
|
+
<title>XiangJsonCraft 示例</title>
|
|
29
|
+
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
|
30
|
+
<!-- 空样式块,由工具自动注入CSS,请勿手动添加样式 -->
|
|
135
31
|
<style id="dynamic-styles"></style>
|
|
136
32
|
</head>
|
|
137
33
|
<body>
|
|
138
|
-
<!--
|
|
139
|
-
<
|
|
140
|
-
<h1></h1>
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
</ul>
|
|
148
|
-
</nav>
|
|
149
|
-
<div class="card">
|
|
150
|
-
<h2></h2>
|
|
151
|
-
<p></p>
|
|
34
|
+
<!-- DOM骨架:选择器与config.json严格对应 -->
|
|
35
|
+
<div class="welcome-container">
|
|
36
|
+
<h1 class="main-title"></h1>
|
|
37
|
+
<p class="subtitle"></p>
|
|
38
|
+
<div class="feature-card">
|
|
39
|
+
<h3 class="feature-title"></h3>
|
|
40
|
+
<p class="feature-desc"></p>
|
|
41
|
+
</div>
|
|
42
|
+
<a href="javascript:;" class="primary-btn"></a>
|
|
152
43
|
</div>
|
|
153
44
|
|
|
154
|
-
<!--
|
|
155
|
-
<script
|
|
156
|
-
import { renderJsonStyles } from './renderJson.js';
|
|
157
|
-
// 一行调用,完成所有样式和内容渲染
|
|
158
|
-
renderJsonStyles();
|
|
159
|
-
</script>
|
|
160
|
-
|
|
161
|
-
<!-- 方式2:CDN全局调用(注释方式1,打开此注释即可) -->
|
|
162
|
-
<!-- <script src="https://cdn.jsdelivr.net/npm/xiangjsoncraft@1.1.1/dist/xiangjsoncraft.umd.js"></script>
|
|
45
|
+
<!-- CDN引入最新版本,全局调用 -->
|
|
46
|
+
<script src="https://cdn.jsdelivr.net/npm/xiangjsoncraft@1.2.0/dist/xiangjsoncraft.umd.js"></script>
|
|
163
47
|
<script>
|
|
164
|
-
|
|
165
|
-
|
|
48
|
+
// 页面加载完成后执行渲染,避免DOM未加载
|
|
49
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
50
|
+
XiangJsonCraft.renderJsonStyles();
|
|
51
|
+
});
|
|
52
|
+
</script>
|
|
166
53
|
</body>
|
|
167
54
|
</html>
|
|
168
55
|
```
|
|
169
|
-
|
|
170
|
-
### 步骤3:开发运行
|
|
171
|
-
```bash
|
|
172
|
-
# 安装开发依赖(首次使用)
|
|
173
|
-
npm install
|
|
174
|
-
|
|
175
|
-
# 打包生成多格式文件(UMD/ES/CJS)
|
|
176
|
-
npm run build
|
|
177
|
-
|
|
178
|
-
# 启动开发服务器,一键预览效果
|
|
179
|
-
npm run dev
|
|
180
|
-
```
|
|
181
|
-
在浏览器中访问 `http://localhost:3000`,即可看到由 JSON 配置渲染的完整页面。
|
|
182
|
-
|
|
183
|
-
## 📚 API 文档
|
|
184
|
-
### `renderJsonStyles()`
|
|
185
|
-
**核心渲染方法**,无入参,执行后自动完成以下操作:
|
|
186
|
-
1. 自动识别运行环境(本地/CDN),加载对应路径的 `config.json` 配置文件
|
|
187
|
-
2. 解析配置中的 `styles` 节点,生成标准 CSS 样式并注入到页面头部的 `#dynamic-styles` 样式块
|
|
188
|
-
3. 解析配置中的 `content` 节点,根据 `isHtml` 标识,向匹配的 DOM 节点注入纯文本/HTML 内容
|
|
189
|
-
4. 控制台输出渲染成功提示,若配置异常则输出友好的错误信息
|
|
190
|
-
|
|
191
|
-
#### 调用方式
|
|
192
|
-
```javascript
|
|
193
|
-
// 方式1:ES6模块化引入(本地开发/前端框架)
|
|
194
|
-
import { renderJsonStyles } from 'xiangjsoncraft';
|
|
195
|
-
renderJsonStyles();
|
|
196
|
-
|
|
197
|
-
// 方式2:CDN全局调用(静态页面/快速开发)
|
|
198
|
-
XiangJsonCraft.renderJsonStyles();
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
## ⚙️ 配置文件说明
|
|
202
|
-
配置文件为标准 JSON 格式,核心包含 `styles` 和 `content` 两个一级节点,所有配置均支持按需扩展、修改。
|
|
203
|
-
|
|
204
|
-
### 1. `styles` 节点
|
|
205
|
-
用于定义页面所有 CSS 样式,**键为任意合法 CSS 选择器**,值为样式属性对象,样式属性支持**驼峰式命名**(会自动转换为 CSS 标准短横线命名)。
|
|
206
|
-
- 支持选择器:类、ID、标签、伪类、伪元素、后代选择器、媒体查询等所有 CSS 合法选择器
|
|
207
|
-
- 样式属性:所有 CSS 原生属性,驼峰式(`fontSize`)会自动转为短横线式(`font-size`)
|
|
208
|
-
|
|
209
|
-
### 2. `content` 节点
|
|
210
|
-
用于定义页面文本/HTML 内容,**键为 CSS 选择器**,值为内容配置对象,包含两个必选属性:
|
|
211
|
-
- `value`:字符串类型,要渲染的内容(纯文本/HTML 片段)
|
|
212
|
-
- `isHtml`:布尔类型,`true` 表示内容为 HTML 片段,`false` 表示内容为纯文本(默认)
|
|
213
|
-
|
|
214
|
-
### 配置文件规范
|
|
215
|
-
1. 配置文件必须命名为 `config.json`,与 HTML 页面同级目录(CDN 方式无需手动创建,自动加载官方配置)
|
|
216
|
-
2. 选择器必须匹配 HTML 中的实际 DOM 节点,否则会被自动过滤
|
|
217
|
-
3. 样式属性值需符合 CSS 规范(如单位、颜色值、尺寸值)
|
|
218
|
-
4. HTML 片段需保证语法合法,避免 XSS 风险(建议仅在可信环境下使用 HTML 内容)
|
|
219
|
-
|
|
220
|
-
## 🎨 配置示例
|
|
221
|
-
### 完整配置示例
|
|
56
|
+
#### 2. 编写config.json(自定义样式+内容,示例可直接复制使用)
|
|
222
57
|
```json
|
|
223
58
|
{
|
|
224
59
|
"styles": {
|
|
225
|
-
// 通配符选择器
|
|
226
60
|
"*": {
|
|
227
|
-
"margin":
|
|
228
|
-
"padding":
|
|
229
|
-
"boxSizing": "border-box"
|
|
61
|
+
"margin": 0,
|
|
62
|
+
"padding": 0,
|
|
63
|
+
"boxSizing": "border-box",
|
|
64
|
+
"fontFamily": "Segoe UI, Roboto, 微软雅黑, sans-serif"
|
|
230
65
|
},
|
|
231
|
-
// 标签选择器
|
|
232
66
|
"body": {
|
|
233
|
-
"
|
|
234
|
-
"
|
|
235
|
-
"
|
|
236
|
-
"
|
|
67
|
+
"backgroundColor": "#f0f4f8",
|
|
68
|
+
"color": "#334e68",
|
|
69
|
+
"lineHeight": "1.6",
|
|
70
|
+
"minHeight": "100vh",
|
|
71
|
+
"padding": "2rem 1rem"
|
|
237
72
|
},
|
|
238
|
-
|
|
239
|
-
"#app": {
|
|
73
|
+
".welcome-container": {
|
|
240
74
|
"maxWidth": "1200px",
|
|
241
75
|
"margin": "0 auto",
|
|
242
76
|
"padding": "2rem"
|
|
243
77
|
},
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
"
|
|
78
|
+
".main-title": {
|
|
79
|
+
"fontSize": "2.2rem",
|
|
80
|
+
"color": "#2d3748",
|
|
81
|
+
"textAlign": "center",
|
|
82
|
+
"marginBottom": "1.5rem",
|
|
83
|
+
"fontWeight": 700
|
|
84
|
+
},
|
|
85
|
+
".subtitle": {
|
|
86
|
+
"fontSize": "1.1rem",
|
|
87
|
+
"color": "#718096",
|
|
88
|
+
"textAlign": "center",
|
|
89
|
+
"maxWidth": "800px",
|
|
90
|
+
"margin": "0 auto 3rem",
|
|
91
|
+
"lineHeight": "1.8"
|
|
92
|
+
},
|
|
93
|
+
".feature-card": {
|
|
94
|
+
"backgroundColor": "#ffffff",
|
|
95
|
+
"borderRadius": "12px",
|
|
96
|
+
"padding": "2rem",
|
|
97
|
+
"boxShadow": "0 4px 12px rgba(0,0,0,0.05)",
|
|
98
|
+
"maxWidth": "600px",
|
|
99
|
+
"margin": "0 auto 2rem",
|
|
100
|
+
"transition": "transform 0.3s ease, boxShadow 0.3s ease"
|
|
101
|
+
},
|
|
102
|
+
".feature-card:hover": {
|
|
103
|
+
"transform": "translateY(-6px)",
|
|
104
|
+
"boxShadow": "0 8px 20px rgba(0,0,0,0.08)"
|
|
105
|
+
},
|
|
106
|
+
".feature-title": {
|
|
107
|
+
"fontSize": "1.4rem",
|
|
108
|
+
"color": "#4299e1",
|
|
109
|
+
"marginBottom": "1rem",
|
|
110
|
+
"fontWeight": 600
|
|
111
|
+
},
|
|
112
|
+
".feature-desc": {
|
|
113
|
+
"color": "#718096",
|
|
114
|
+
"lineHeight": "1.7"
|
|
115
|
+
},
|
|
116
|
+
".primary-btn": {
|
|
117
|
+
"display": "block",
|
|
118
|
+
"width": "200px",
|
|
119
|
+
"height": "50px",
|
|
120
|
+
"lineHeight": "50px",
|
|
121
|
+
"textAlign": "center",
|
|
122
|
+
"backgroundColor": "#4299e1",
|
|
123
|
+
"color": "#ffffff",
|
|
247
124
|
"border": "none",
|
|
248
|
-
"borderRadius": "
|
|
125
|
+
"borderRadius": "8px",
|
|
126
|
+
"margin": "0 auto",
|
|
127
|
+
"fontSize": "1rem",
|
|
128
|
+
"fontWeight": 600,
|
|
249
129
|
"cursor": "pointer",
|
|
250
|
-
"
|
|
130
|
+
"transition": "backgroundColor 0.3s ease, transform 0.2s ease",
|
|
131
|
+
"textDecoration": "none"
|
|
251
132
|
},
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
"
|
|
255
|
-
"color": "white"
|
|
133
|
+
".primary-btn:hover": {
|
|
134
|
+
"backgroundColor": "#3182ce",
|
|
135
|
+
"transform": "translateY(-2px)"
|
|
256
136
|
},
|
|
257
|
-
".btn
|
|
258
|
-
"
|
|
137
|
+
".primary-btn:active": {
|
|
138
|
+
"transform": "translateY(0)",
|
|
139
|
+
"backgroundColor": "#2b6cb0"
|
|
259
140
|
},
|
|
260
|
-
// 媒体查询
|
|
261
141
|
"@media (max-width: 768px)": {
|
|
262
|
-
"
|
|
142
|
+
".main-title": {
|
|
143
|
+
"fontSize": "1.8rem"
|
|
144
|
+
},
|
|
145
|
+
".welcome-container": {
|
|
263
146
|
"padding": "1rem"
|
|
264
147
|
},
|
|
265
|
-
".
|
|
266
|
-
"
|
|
267
|
-
"marginBottom": "1rem"
|
|
148
|
+
".feature-card": {
|
|
149
|
+
"padding": "1.5rem"
|
|
268
150
|
}
|
|
269
151
|
}
|
|
270
152
|
},
|
|
271
153
|
"content": {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
"value": "XiangJsonCraft 配置示例",
|
|
154
|
+
".main-title": {
|
|
155
|
+
"value": "XiangJsonCraft 快速示例",
|
|
275
156
|
"isHtml": false
|
|
276
157
|
},
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
"
|
|
158
|
+
".subtitle": {
|
|
159
|
+
"value": "基于JSON配置渲染的网页,无需手写CSS,修改JSON即可定制所有样式和内容!",
|
|
160
|
+
"isHtml": false
|
|
161
|
+
},
|
|
162
|
+
".feature-title": {
|
|
163
|
+
"value": "核心特色:JSON完全解耦",
|
|
164
|
+
"isHtml": false
|
|
165
|
+
},
|
|
166
|
+
".feature-desc": {
|
|
167
|
+
"value": "HTML仅负责搭建DOM骨架,样式、文本/HTML内容全由JSON控制,后期维护只需修改JSON,无需触碰HTML/JS代码,非前端开发者也能轻松使用。",
|
|
168
|
+
"isHtml": false
|
|
169
|
+
},
|
|
170
|
+
".primary-btn": {
|
|
171
|
+
"value": "<span onclick=\"window.open('https://www.npmjs.com/package/xiangjsoncraft', '_blank')\">查看NPM官方文档</span>",
|
|
280
172
|
"isHtml": true
|
|
281
173
|
}
|
|
282
174
|
}
|
|
283
175
|
}
|
|
284
176
|
```
|
|
177
|
+
#### 3. 运行项目
|
|
178
|
+
将两个文件放在同一文件夹,使用**VS Code Live Server**(或其他本地服务器)打开`index.html`(必须用服务器打开,避免浏览器跨域阻止加载本地JSON)。
|
|
285
179
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
某天,朋友在Vue项目里用这个包时,遇到了个不符合自己编程习惯的小细节,对着node_modules里的代码犯愁:“老师说这地方不能随便改,容易牵一发而动全身。”
|
|
292
|
-
|
|
293
|
-
我当时笑着回了句:“没事,改不坏。”朋友反问:“你怎么这么自信?难道你会用?”
|
|
294
|
-
|
|
295
|
-
我故意顿了顿,笑着说:“哼?我会吗……”
|
|
296
|
-
|
|
297
|
-
其实不是“会用”,是“会造”——整个包的每一行代码,都是我从0到1敲出来的。哪里是样式配置的核心逻辑,哪部分是内容渲染的关键节点,甚至每个变量命名的小心思,早就刻在脑子里了。
|
|
298
|
-
|
|
299
|
-
对别人来说,改node_modules是“碰别人的代码”;但对我来说,改的是“自己写的工具”。知道怎么调整既不破坏核心功能,又能贴合朋友的习惯,这份底气,其实来自“开发者”这个身份最本质的掌控感。
|
|
300
|
-
|
|
301
|
-
所以如果你用的时候也有小想法,不用怕“改坏”——工具本身就为“灵活适配”留足了空间,而作为作者,我也始终在背后,为它的稳定和好用托底。
|
|
302
|
-
|
|
303
|
-
## 🌐 浏览器兼容性
|
|
304
|
-
支持所有现代浏览器,无需额外引入 polyfill:
|
|
305
|
-
- Chrome ≥ 61
|
|
306
|
-
- Firefox ≥ 60
|
|
307
|
-
- Edge ≥ 79
|
|
308
|
-
- Safari ≥ 12.1
|
|
309
|
-
- Opera ≥ 48
|
|
310
|
-
- 移动端所有现代浏览器(微信浏览器、QQ浏览器、Safari 移动端等)
|
|
311
|
-
|
|
312
|
-
## 🤝 贡献指南
|
|
313
|
-
XiangJsonCraft 欢迎所有开发者的贡献和建议,如果你有以下想法,欢迎随时交流:
|
|
314
|
-
- 新增功能需求
|
|
315
|
-
- 性能优化建议
|
|
316
|
-
- Bug 修复
|
|
317
|
-
- 文档完善
|
|
318
|
-
|
|
319
|
-
**贡献方式**:通过邮箱联系作者,提供你的想法、代码或问题描述,作者会第一时间回复。
|
|
320
|
-
|
|
321
|
-
## 📄 许可证
|
|
322
|
-
本项目基于 **MIT 开源许可证** 发布,你可以自由使用、修改、分发本项目,无需支付任何费用,只需保留版权声明。
|
|
323
|
-
|
|
180
|
+
### 方式2:NPM安装(本地开发,集成到现有项目)
|
|
181
|
+
#### 1. 安装包
|
|
182
|
+
```bash
|
|
183
|
+
npm install xiangjsoncraft --save
|
|
324
184
|
```
|
|
325
|
-
|
|
326
|
-
Copyright (c) 2025 董翔
|
|
327
|
-
|
|
328
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
329
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
330
|
-
in the Software without restriction, including without limitation the rights
|
|
331
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
332
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
333
|
-
furnished to do so, subject to the following conditions:
|
|
334
|
-
|
|
335
|
-
The above copyright notice and this permission notice shall be included in all
|
|
336
|
-
copies or substantial portions of the Software.
|
|
337
|
-
|
|
338
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
339
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
340
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
341
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
342
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
343
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
344
|
-
SOFTWARE.
|
|
185
|
+
#### 2. 项目目录(集成到现有项目)
|
|
345
186
|
```
|
|
187
|
+
your-project/
|
|
188
|
+
├─ src/
|
|
189
|
+
│ ├─ index.html # 项目入口页面(DOM骨架)
|
|
190
|
+
│ ├─ config.json # 自定义配置文件
|
|
191
|
+
│ └─ main.js # 入口JS,引入并调用渲染函数
|
|
192
|
+
└─ package.json
|
|
193
|
+
```
|
|
194
|
+
#### 3. 编写main.js(模块化引入)
|
|
195
|
+
```javascript
|
|
196
|
+
// 模块化引入核心渲染函数
|
|
197
|
+
import { renderJsonStyles } from 'xiangjsoncraft';
|
|
346
198
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
199
|
+
// 页面加载完成后执行
|
|
200
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
201
|
+
renderJsonStyles();
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
#### 4. 运行项目
|
|
205
|
+
通过项目的构建工具(Vite/Webpack/Parcel等)运行,确保本地服务器能正常访问`config.json`。
|
|
206
|
+
|
|
207
|
+
## 配置文件说明(config.json)
|
|
208
|
+
配置文件包含`styles`和`content`两个核心节点,**均为对象格式**,选择器需与HTML中的DOM严格对应,JSON语法需合法(推荐用[JSON.cn](https://www.json.cn/)校验)。
|
|
209
|
+
|
|
210
|
+
### 1. styles 节点:样式配置
|
|
211
|
+
- 用于定义所有CSS样式,**支持所有合法CSS选择器**(全局`*`、类、ID、伪类、媒体查询`@media`等);
|
|
212
|
+
- 样式属性名**支持驼峰命名**(如`boxSizing`),工具会自动转换为CSS标准短横线命名(`box-sizing`);
|
|
213
|
+
- 属性值为**CSS合法值字符串/数字**(如`"2rem"`、`100%`、`700`),工具会自动转字符串处理;
|
|
214
|
+
- 支持**hover/active**等伪类、**transition**过渡动画、**@media**响应式布局,写法与CSS一致。
|
|
215
|
+
|
|
216
|
+
#### 关键规则
|
|
217
|
+
- 选择器不能为空,且必须为字符串;
|
|
218
|
+
- 每个选择器对应的值必须为**对象**(不能是数组/字符串/数字);
|
|
219
|
+
- 空属性、无效属性值会被自动过滤,不影响整体渲染。
|
|
220
|
+
|
|
221
|
+
### 2. content 节点:内容配置
|
|
222
|
+
- 用于向DOM节点注入文本或HTML内容,**键为与HTML对应的选择器**,值为内容配置对象;
|
|
223
|
+
- 内容配置对象包含2个属性:
|
|
224
|
+
| 属性 | 类型 | 必选 | 默认值 | 说明 |
|
|
225
|
+
| ------ | ------- | ---- | ------ | ------------------------------------------ |
|
|
226
|
+
| value | 任意 | 是 | - | 要注入的文本/HTML内容 |
|
|
227
|
+
| isHtml | Boolean | 否 | false | 是否以HTML格式渲染,false为纯文本(防XSS) |
|
|
228
|
+
|
|
229
|
+
#### 关键规则
|
|
230
|
+
- 选择器需与HTML严格对应,不存在的选择器会被自动过滤;
|
|
231
|
+
- 必须包含`value`属性,否则该节点会被过滤;
|
|
232
|
+
- `isHtml: true`时,`value`支持HTML标签和原生JS事件(如`onclick`),适合实现简单交互。
|
|
233
|
+
|
|
234
|
+
## 核心函数说明
|
|
235
|
+
### renderJsonStyles()
|
|
236
|
+
- 核心渲染函数,无入参,调用后自动执行以下逻辑:
|
|
237
|
+
1. 优先加载**与HTML同级的本地config.json**,控制台打印`🔧 检测到本地config.json,优先加载用户自定义配置`;
|
|
238
|
+
2. 若本地无config.json,自动加载**CDN官方示例配置**,控制台打印`ℹ️ 本地未检测到config.json,加载CDN官方示例配置`;
|
|
239
|
+
3. 解析样式配置,生成格式化的CSS代码,注入到页面的`#dynamic-styles`样式块;
|
|
240
|
+
4. 解析内容配置,根据选择器向对应DOM节点注入文本/HTML内容;
|
|
241
|
+
5. 渲染成功打印`✅ XiangJsonCraft 渲染成功!样式+内容已全部加载`,失败则打印具体错误信息。
|
|
242
|
+
|
|
243
|
+
## 浏览器控制台日志说明
|
|
244
|
+
工具会打印清晰的日志,方便排查问题,日志分类如下:
|
|
245
|
+
| 日志级别 | 前缀 | 说明 |
|
|
246
|
+
| -------- | ---- | -------------------------- |
|
|
247
|
+
| 信息 | 🔧/ℹ️ | 配置加载状态提示 |
|
|
248
|
+
| 成功 | ✅ | 渲染成功提示 |
|
|
249
|
+
| 错误 | ❌ | 渲染失败(含具体错误原因) |
|
|
250
|
+
|
|
251
|
+
## 常见问题排查
|
|
252
|
+
### 1. 控制台报404错误:无法加载config.json
|
|
253
|
+
- 原因:未用本地服务器打开页面,浏览器跨域策略阻止加载本地文件;
|
|
254
|
+
- 解决:使用VS Code Live Server/Node.js Express等本地服务器打开,确保JSON文件可通过服务器访问。
|
|
255
|
+
|
|
256
|
+
### 2. 控制台报错:prop.replaceCamelCase is not a function
|
|
257
|
+
- 原因:styles节点中存在**非字符串类型的属性名**(如数字、null);
|
|
258
|
+
- 解决:校验JSON语法,确保所有属性名为**双引号包裹的字符串**,删除无效属性。
|
|
259
|
+
|
|
260
|
+
### 3. 样式未渲染/内容未注入
|
|
261
|
+
- 检查选择器:HTML中的DOM选择器与JSON中的键**严格一致**(区分大小写、类名前缀`.`);
|
|
262
|
+
- 检查JSON语法:确保无语法错误(如缺少引号、大括号,逗号结尾);
|
|
263
|
+
- 检查日志:根据控制台日志判断配置文件是否被正确加载。
|
|
264
|
+
|
|
265
|
+
### 4. 浏览器标签页报favicon.ico 404
|
|
266
|
+
- 原因:浏览器默认在项目根目录找网站小图标,未找到则报404;
|
|
267
|
+
- 解决:下载`favicon.ico`图标放到项目根目录,或在HTML的`<head>`中通过`<link rel="icon">`指定PNG/SVG图标。
|
|
268
|
+
|
|
269
|
+
## 开发与打包
|
|
270
|
+
### 1. 克隆源码
|
|
271
|
+
```bash
|
|
272
|
+
git clone https://github.com/你的GitHub用户名/xiangjsoncraft.git
|
|
273
|
+
cd xiangjsoncraft
|
|
274
|
+
```
|
|
275
|
+
### 2. 安装开发依赖
|
|
276
|
+
```bash
|
|
277
|
+
npm install
|
|
278
|
+
```
|
|
279
|
+
### 3. 打包构建
|
|
280
|
+
使用Rollup打包为**UMD格式**(兼容模块化、CDN全局调用、CommonJS),打包后输出到`dist`目录:
|
|
281
|
+
```bash
|
|
282
|
+
npm run build
|
|
283
|
+
```
|
|
284
|
+
### 4. 本地测试
|
|
285
|
+
打包后,可将`dist`目录中的`xiangjsoncraft.umd.js`与示例`index.html`、`config.json`放在一起,通过本地服务器测试。
|
|
286
|
+
|
|
287
|
+
## 版本更新日志
|
|
288
|
+
### v1.2.0(最新稳定版)
|
|
289
|
+
- 核心优化:**本地config.json永远最高优先级**,兼容CDN/本地引入两种方式;
|
|
290
|
+
- 全量容错:过滤无效选择器、非字符串属性名、空属性值,单个配置错误不影响整体渲染;
|
|
291
|
+
- 样式优化:生成的CSS自动格式化(带缩进),易调试,样式块插入到head最前面避免被覆盖;
|
|
292
|
+
- 体验优化:新增友好控制台日志,区分配置加载状态、渲染成功/失败;
|
|
293
|
+
- 细节完善:支持SVG/PNG网站小图标,解决favicon.ico 404问题;
|
|
294
|
+
- 兼容优化:暴露全局变量`window.XiangJsonCraft`,CDN引入可直接全局调用。
|
|
295
|
+
|
|
296
|
+
### v1.1.1
|
|
297
|
+
- 首次正式发布,实现核心JSON解耦渲染功能;
|
|
298
|
+
- 支持CDN/本地引入,基本样式和内容渲染;
|
|
299
|
+
- 支持驼峰属性自动转换,媒体查询、伪类样式。
|
|
300
|
+
|
|
301
|
+
## 开源协议
|
|
302
|
+
MIT License - 详见项目根目录`LICENSE`文件,可自由使用、修改、分发,无需授权。
|
|
303
|
+
|
|
304
|
+
## 官方地址
|
|
305
|
+
- NPM:https://www.npmjs.com/package/xiangjsoncraft
|
|
306
|
+
- Github:https://github.com/dxiangwiki/xiangjsoncraft
|
|
307
|
+
## 问题反馈
|
|
308
|
+
若使用过程中遇到问题,可在GitHub仓库提交Issue,或通过NPM包主页留言,会及时响应并修复。
|
package/config.json
CHANGED
|
@@ -1,218 +1,113 @@
|
|
|
1
1
|
{
|
|
2
2
|
"styles": {
|
|
3
3
|
"*": {
|
|
4
|
-
"margin":
|
|
5
|
-
"padding":
|
|
4
|
+
"margin": 0,
|
|
5
|
+
"padding": 0,
|
|
6
6
|
"boxSizing": "border-box",
|
|
7
|
-
"fontFamily": "
|
|
7
|
+
"fontFamily": "Segoe UI, Roboto, 微软雅黑, sans-serif"
|
|
8
8
|
},
|
|
9
9
|
"body": {
|
|
10
10
|
"backgroundColor": "#f0f4f8",
|
|
11
11
|
"color": "#334e68",
|
|
12
12
|
"lineHeight": "1.6",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
13
|
+
"minHeight": "100vh",
|
|
14
|
+
"padding": "2rem 1rem"
|
|
15
15
|
},
|
|
16
16
|
".welcome-container": {
|
|
17
17
|
"maxWidth": "1200px",
|
|
18
18
|
"margin": "0 auto",
|
|
19
|
-
"padding": "
|
|
20
|
-
},
|
|
21
|
-
".welcome-header": {
|
|
22
|
-
"textAlign": "center",
|
|
23
|
-
"padding": "60px 20px",
|
|
24
|
-
"marginBottom": "40px",
|
|
25
|
-
"borderRadius": "12px",
|
|
26
|
-
"background": "linear-gradient(135deg, #4299e1, #63b3ed)",
|
|
27
|
-
"color": "white",
|
|
28
|
-
"boxShadow": "0 10px 25px -5px rgba(66, 153, 225, 0.3)",
|
|
29
|
-
"transition": "transform 0.5s ease, boxShadow 0.5s ease"
|
|
30
|
-
},
|
|
31
|
-
".welcome-header:hover": {
|
|
32
|
-
"transform": "translateY(-5px)",
|
|
33
|
-
"boxShadow": "0 15px 30px -8px rgba(66, 153, 225, 0.4)"
|
|
34
|
-
},
|
|
35
|
-
".logo-container": {
|
|
36
|
-
"marginBottom": "30px"
|
|
37
|
-
},
|
|
38
|
-
".logo": {
|
|
39
|
-
"width": "120px",
|
|
40
|
-
"height": "120px",
|
|
41
|
-
"margin": "0 auto",
|
|
42
|
-
"backgroundColor": "white",
|
|
43
|
-
"borderRadius": "50%",
|
|
44
|
-
"display": "flex",
|
|
45
|
-
"alignItems": "center",
|
|
46
|
-
"justifyContent": "center",
|
|
47
|
-
"fontSize": "48px",
|
|
48
|
-
"color": "#4299e1",
|
|
49
|
-
"boxShadow": "0 4px 12px rgba(0, 0, 0, 0.1)"
|
|
50
|
-
},
|
|
51
|
-
".logo::after": {
|
|
52
|
-
"content": "'J'",
|
|
53
|
-
"fontWeight": "bold"
|
|
19
|
+
"padding": "2rem"
|
|
54
20
|
},
|
|
55
21
|
".main-title": {
|
|
56
|
-
"fontSize": "2.
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
".main-title": {
|
|
62
|
-
"fontSize": "2rem"
|
|
63
|
-
}
|
|
22
|
+
"fontSize": "2.2rem",
|
|
23
|
+
"color": "#2d3748",
|
|
24
|
+
"textAlign": "center",
|
|
25
|
+
"marginBottom": "1.5rem",
|
|
26
|
+
"fontWeight": 700
|
|
64
27
|
},
|
|
65
28
|
".subtitle": {
|
|
66
29
|
"fontSize": "1.1rem",
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"display": "grid",
|
|
73
|
-
"gridTemplateColumns": "repeat(auto-fit, minmax(300px, 1fr))",
|
|
74
|
-
"gap": "30px",
|
|
75
|
-
"marginBottom": "60px"
|
|
30
|
+
"color": "#718096",
|
|
31
|
+
"textAlign": "center",
|
|
32
|
+
"maxWidth": "800px",
|
|
33
|
+
"margin": "0 auto 3rem",
|
|
34
|
+
"lineHeight": "1.8"
|
|
76
35
|
},
|
|
77
36
|
".feature-card": {
|
|
78
|
-
"backgroundColor": "
|
|
37
|
+
"backgroundColor": "#ffffff",
|
|
79
38
|
"borderRadius": "12px",
|
|
80
|
-
"padding": "
|
|
81
|
-
"boxShadow": "0 4px 12px rgba(0,
|
|
39
|
+
"padding": "2rem",
|
|
40
|
+
"boxShadow": "0 4px 12px rgba(0,0,0,0.05)",
|
|
41
|
+
"maxWidth": "600px",
|
|
42
|
+
"margin": "0 auto 2rem",
|
|
82
43
|
"transition": "transform 0.3s ease, boxShadow 0.3s ease"
|
|
83
44
|
},
|
|
84
45
|
".feature-card:hover": {
|
|
85
|
-
"transform": "translateY(-
|
|
86
|
-
"boxShadow": "0
|
|
87
|
-
},
|
|
88
|
-
".feature-icon": {
|
|
89
|
-
"width": "60px",
|
|
90
|
-
"height": "60px",
|
|
91
|
-
"borderRadius": "12px",
|
|
92
|
-
"backgroundColor": "#ebf8ff",
|
|
93
|
-
"color": "#4299e1",
|
|
94
|
-
"display": "flex",
|
|
95
|
-
"alignItems": "center",
|
|
96
|
-
"justifyContent": "center",
|
|
97
|
-
"fontSize": "24px",
|
|
98
|
-
"marginBottom": "20px"
|
|
46
|
+
"transform": "translateY(-6px)",
|
|
47
|
+
"boxShadow": "0 8px 20px rgba(0,0,0,0.08)"
|
|
99
48
|
},
|
|
100
49
|
".feature-title": {
|
|
101
|
-
"fontSize": "1.
|
|
102
|
-
"
|
|
103
|
-
"
|
|
50
|
+
"fontSize": "1.4rem",
|
|
51
|
+
"color": "#4299e1",
|
|
52
|
+
"marginBottom": "1rem",
|
|
53
|
+
"fontWeight": 600
|
|
104
54
|
},
|
|
105
|
-
".feature-
|
|
55
|
+
".feature-desc": {
|
|
106
56
|
"color": "#718096",
|
|
107
57
|
"lineHeight": "1.7"
|
|
108
58
|
},
|
|
109
|
-
".
|
|
59
|
+
".primary-btn": {
|
|
60
|
+
"display": "block",
|
|
61
|
+
"width": "200px",
|
|
62
|
+
"height": "50px",
|
|
63
|
+
"lineHeight": "50px",
|
|
110
64
|
"textAlign": "center",
|
|
111
|
-
"marginBottom": "80px"
|
|
112
|
-
},
|
|
113
|
-
".primary-button": {
|
|
114
65
|
"backgroundColor": "#4299e1",
|
|
115
|
-
"color": "
|
|
66
|
+
"color": "#ffffff",
|
|
116
67
|
"border": "none",
|
|
117
68
|
"borderRadius": "8px",
|
|
118
|
-
"
|
|
69
|
+
"margin": "0 auto",
|
|
119
70
|
"fontSize": "1rem",
|
|
120
|
-
"fontWeight":
|
|
71
|
+
"fontWeight": 600,
|
|
121
72
|
"cursor": "pointer",
|
|
122
|
-
"transition": "
|
|
123
|
-
"boxShadow": "0 4px 6px rgba(66, 153, 225, 0.2)"
|
|
73
|
+
"transition": "backgroundColor 0.3s ease, transform 0.2s ease"
|
|
124
74
|
},
|
|
125
|
-
".primary-
|
|
75
|
+
".primary-btn:hover": {
|
|
126
76
|
"backgroundColor": "#3182ce",
|
|
127
|
-
"transform": "translateY(-2px)"
|
|
128
|
-
"boxShadow": "0 6px 10px rgba(66, 153, 225, 0.3)"
|
|
77
|
+
"transform": "translateY(-2px)"
|
|
129
78
|
},
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
|
|
133
|
-
"fontSize": "0.95rem"
|
|
134
|
-
},
|
|
135
|
-
".page-footer": {
|
|
136
|
-
"textAlign": "center",
|
|
137
|
-
"paddingTop": "30px",
|
|
138
|
-
"borderTop": "1px solid #e2e8f0",
|
|
139
|
-
"color": "#718096"
|
|
140
|
-
},
|
|
141
|
-
".copyright": {
|
|
142
|
-
"marginBottom": "15px",
|
|
143
|
-
"fontSize": "0.9rem"
|
|
144
|
-
},
|
|
145
|
-
".social-links": {
|
|
146
|
-
"display": "flex",
|
|
147
|
-
"justifyContent": "center",
|
|
148
|
-
"gap": "15px"
|
|
149
|
-
},
|
|
150
|
-
".social-icon": {
|
|
151
|
-
"color": "#718096",
|
|
152
|
-
"fontSize": "1.2rem",
|
|
153
|
-
"transition": "color 0.3s ease"
|
|
154
|
-
},
|
|
155
|
-
".social-icon:hover": {
|
|
156
|
-
"color": "#4299e1"
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
"body:not(.loaded) .welcome-header": {
|
|
160
|
-
"opacity": "0",
|
|
161
|
-
"transform": "translateY(20px)"
|
|
162
|
-
},
|
|
163
|
-
"body.loaded .welcome-header": {
|
|
164
|
-
"opacity": "1",
|
|
165
|
-
"transform": "translateY(0)",
|
|
166
|
-
"transition": "opacity 0.8s ease, transform 0.8s ease"
|
|
167
|
-
},
|
|
168
|
-
"body:not(.loaded) .feature-card": {
|
|
169
|
-
"opacity": "0",
|
|
170
|
-
"transform": "scale(0.95)"
|
|
171
|
-
},
|
|
172
|
-
"body.loaded .feature-card": {
|
|
173
|
-
"opacity": "1",
|
|
174
|
-
"transform": "scale(1)",
|
|
175
|
-
"transition": "opacity 0.6s ease, transform 0.6s ease"
|
|
176
|
-
},
|
|
177
|
-
"body.loaded .feature-card:nth-child(1)": { "transitionDelay": "0.2s" },
|
|
178
|
-
"body.loaded .feature-card:nth-child(2)": { "transitionDelay": "0.4s" },
|
|
179
|
-
"body.loaded .feature-card:nth-child(3)": { "transitionDelay": "0.6s" }
|
|
180
|
-
},
|
|
181
|
-
"content": {
|
|
182
|
-
".main-title": "Welcome to xiangjsoncraft",
|
|
183
|
-
".subtitle": "Create beautiful web pages with simple JSON configuration",
|
|
184
|
-
".primary-button": "Get Started",
|
|
185
|
-
".additional-info": "Join thousands of developers using our JSON configuration system",
|
|
186
|
-
".copyright": "© 2025 Dong Xiang. All rights reserved."
|
|
187
|
-
},
|
|
188
|
-
"features": {
|
|
189
|
-
"selectorPrefix": "#feature",
|
|
190
|
-
"items": [
|
|
191
|
-
{
|
|
192
|
-
"iconClass": "fas fa-code",
|
|
193
|
-
"title": "Simple Configuration",
|
|
194
|
-
"description": "Define your entire page style and content with easy-to-understand JSON"
|
|
79
|
+
"@media (max-width: 768px)": {
|
|
80
|
+
".main-title": {
|
|
81
|
+
"fontSize": "1.8rem"
|
|
195
82
|
},
|
|
196
|
-
{
|
|
197
|
-
"
|
|
198
|
-
"title": "Beautiful Designs",
|
|
199
|
-
"description": "Create stunning interfaces without writing complex CSS code"
|
|
83
|
+
".welcome-container": {
|
|
84
|
+
"padding": "1rem"
|
|
200
85
|
},
|
|
201
|
-
{
|
|
202
|
-
"
|
|
203
|
-
"title": "Responsive by Default",
|
|
204
|
-
"description": "Your pages will look great on all devices with built-in responsiveness"
|
|
86
|
+
".feature-card": {
|
|
87
|
+
"padding": "1.5rem"
|
|
205
88
|
}
|
|
206
|
-
|
|
89
|
+
}
|
|
207
90
|
},
|
|
208
|
-
"
|
|
209
|
-
"
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
91
|
+
"content": {
|
|
92
|
+
".main-title": {
|
|
93
|
+
"value": "XiangJsonCraft 测试页面",
|
|
94
|
+
"isHtml": false
|
|
95
|
+
},
|
|
96
|
+
".subtitle": {
|
|
97
|
+
"value": "基于JSON配置渲染的页面,无需手写CSS,修改JSON即可定制样式和内容!",
|
|
98
|
+
"isHtml": false
|
|
99
|
+
},
|
|
100
|
+
".feature-title": {
|
|
101
|
+
"value": "核心特色:JSON解耦",
|
|
102
|
+
"isHtml": false
|
|
103
|
+
},
|
|
104
|
+
".feature-desc": {
|
|
105
|
+
"value": "HTML仅负责搭建DOM骨架,样式、内容全由JSON控制,后期维护只需修改JSON,无需触碰HTML/JS代码。",
|
|
106
|
+
"isHtml": false
|
|
107
|
+
},
|
|
108
|
+
".primary-btn": {
|
|
109
|
+
"value": "<span onclick=\"window.open('https://www.npmjs.com/package/xiangjsoncraft', '_blank')\">点我查看 NPM 包地址</span>",
|
|
110
|
+
"isHtml": true
|
|
111
|
+
}
|
|
216
112
|
}
|
|
217
|
-
}
|
|
218
|
-
|
|
113
|
+
}
|
package/package.json
CHANGED
package/renderJson.js
CHANGED
|
@@ -1,82 +1,133 @@
|
|
|
1
|
-
//
|
|
1
|
+
// 为String原型扩展驼峰转短横线方法,用于CSS属性名转换
|
|
2
|
+
String.prototype.replaceCamelCase = function (separator = '-') {
|
|
3
|
+
// 容错:如果是纯数字/无驼峰的字符串,直接返回
|
|
4
|
+
return this.replace(/[A-Z]/g, (match) => `${separator}${match.toLowerCase()}`);
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// 创建样式块并添加到文档头部,确保唯一且不重复创建
|
|
8
|
+
function createStyleBlock() {
|
|
9
|
+
const style = document.createElement('style');
|
|
10
|
+
style.id = 'dynamic-styles';
|
|
11
|
+
// 把样式块插入到head最前面,避免被其他样式覆盖
|
|
12
|
+
document.head.insertBefore(style, document.head.firstChild);
|
|
13
|
+
return style;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 核心渲染函数:本地config.json最高优先级,CDN配置兜底,全量容错
|
|
2
17
|
export function renderJsonStyles() {
|
|
3
|
-
//
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
.
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
// 配置地址:本地自定义(最高优先级) + CDN官方兜底
|
|
19
|
+
const LOCAL_CONFIG = './config.json';
|
|
20
|
+
const CDN_CONFIG = 'https://cdn.jsdelivr.net/npm/xiangjsoncraft@1.1.1/config.json';
|
|
21
|
+
|
|
22
|
+
// 统一错误处理函数,避免单个错误中断整体渲染
|
|
23
|
+
const handleError = (msg) => {
|
|
24
|
+
console.error(`❌ XiangJsonCraft 错误: ${msg}`);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// 核心逻辑:先加载本地配置,失败则加载CDN兜底配置
|
|
28
|
+
fetch(LOCAL_CONFIG)
|
|
29
|
+
.then(async (res) => {
|
|
30
|
+
// 本地配置存在(状态码200-299),使用本地配置
|
|
31
|
+
if (res.ok) {
|
|
12
32
|
console.log('🔧 检测到本地config.json,优先加载用户自定义配置');
|
|
13
|
-
return
|
|
33
|
+
return res.json();
|
|
14
34
|
}
|
|
15
|
-
// 本地配置不存在/加载失败,切换到CDN
|
|
35
|
+
// 本地配置不存在/加载失败,切换到CDN配置
|
|
16
36
|
console.log('ℹ️ 本地未检测到config.json,加载CDN官方示例配置');
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
});
|
|
37
|
+
const cdnRes = await fetch(CDN_CONFIG);
|
|
38
|
+
if (!cdnRes.ok) throw new Error('CDN官方配置加载失败,请检查网络');
|
|
39
|
+
return cdnRes.json();
|
|
21
40
|
})
|
|
22
|
-
.then(config => {
|
|
23
|
-
//
|
|
41
|
+
.then((config) => {
|
|
42
|
+
// 容错:如果配置不是对象,直接终止渲染
|
|
43
|
+
if (typeof config !== 'object' || config === null || Array.isArray(config)) {
|
|
44
|
+
return handleError('配置文件格式错误,必须是标准JSON对象');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 获取/创建样式块,确保渲染容器存在
|
|
24
48
|
const styleBlock = document.getElementById('dynamic-styles') || createStyleBlock();
|
|
25
|
-
if (!styleBlock) return
|
|
49
|
+
if (!styleBlock) return handleError('样式块创建失败,无法渲染CSS');
|
|
26
50
|
|
|
27
|
-
// 生成CSS
|
|
51
|
+
// 生成CSS规则:处理styles节点,全量容错+格式美化
|
|
28
52
|
let cssRules = '';
|
|
53
|
+
const { styles = {} } = config; // 解构赋值,避免styles未定义
|
|
29
54
|
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
// 遍历所有CSS选择器(支持类、ID、媒体查询等所有合法选择器)
|
|
56
|
+
Object.entries(styles).forEach(([selector, styleObj]) => {
|
|
57
|
+
// 容错1:选择器为空/非字符串,跳过
|
|
58
|
+
const selectorStr = String(selector).trim();
|
|
59
|
+
if (!selectorStr) return;
|
|
60
|
+
// 容错2:选择器对应的不是样式对象,跳过
|
|
61
|
+
if (typeof styleObj !== 'object' || styleObj === null || Array.isArray(styleObj)) return;
|
|
62
|
+
|
|
63
|
+
// 处理单个选择器下的所有样式属性
|
|
64
|
+
const styleProps = Object.entries(styleObj)
|
|
65
|
+
.map(([prop, value]) => {
|
|
66
|
+
// 容错3:属性名强制转字符串+去空格,空属性直接跳过
|
|
67
|
+
const propStr = String(prop).trim();
|
|
68
|
+
if (!propStr) return '';
|
|
69
|
+
// 容错4:属性值为空/无效,直接跳过
|
|
70
|
+
if (value === undefined || value === null || String(value).trim() === '') return '';
|
|
71
|
+
// 驼峰属性名转CSS标准短横线(如fontSize → font-size)
|
|
72
|
+
const cssProp = propStr.replaceCamelCase();
|
|
73
|
+
// 属性值强制转字符串,避免数字/布尔值渲染异常
|
|
74
|
+
const cssValue = String(value).trim();
|
|
75
|
+
// 返回合法的CSS属性行
|
|
76
|
+
return `${cssProp}: ${cssValue};`;
|
|
77
|
+
})
|
|
78
|
+
.filter(Boolean) // 过滤所有空字符串,只留合法属性
|
|
79
|
+
.join('\n '); // 拼接成带缩进的整洁CSS
|
|
80
|
+
|
|
81
|
+
// 只有当有合法样式属性时,才生成CSS规则,避免空选择器
|
|
82
|
+
if (styleProps) {
|
|
83
|
+
cssRules += `${selectorStr} {\n ${styleProps}\n}\n\n`;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
53
86
|
|
|
54
|
-
//
|
|
87
|
+
// 将生成的CSS注入到样式块,覆盖原有内容(避免重复渲染)
|
|
55
88
|
if (cssRules) {
|
|
56
89
|
styleBlock.innerHTML = cssRules;
|
|
57
90
|
}
|
|
58
91
|
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
92
|
+
// 渲染内容:处理content节点,向DOM注入文本/HTML
|
|
93
|
+
const { content = {} } = config; // 解构赋值,避免content未定义
|
|
94
|
+
Object.entries(content).forEach(([selector, contentObj]) => {
|
|
95
|
+
// 容错1:选择器为空/非字符串,跳过
|
|
96
|
+
const selectorStr = String(selector).trim();
|
|
97
|
+
if (!selectorStr) return;
|
|
98
|
+
// 容错2:内容配置不是对象,跳过
|
|
99
|
+
if (typeof contentObj !== 'object' || contentObj === null || Array.isArray(contentObj)) return;
|
|
100
|
+
// 容错3:缺少核心的value属性,跳过
|
|
101
|
+
if (!contentObj.hasOwnProperty('value')) return;
|
|
102
|
+
|
|
103
|
+
// 获取要注入内容的DOM节点,容错:节点不存在则跳过
|
|
104
|
+
const targetNodes = document.querySelectorAll(selectorStr);
|
|
105
|
+
if (targetNodes.length === 0) return;
|
|
106
|
+
|
|
107
|
+
// 解析内容配置:isHtml默认为false(纯文本)
|
|
108
|
+
const { value, isHtml = false } = contentObj;
|
|
109
|
+
const contentValue = String(value).trim(); // 内容强制转字符串,避免异常
|
|
110
|
+
|
|
111
|
+
// 向所有匹配的DOM节点注入内容
|
|
112
|
+
targetNodes.forEach((node) => {
|
|
113
|
+
if (isHtml) {
|
|
114
|
+
node.innerHTML = contentValue; // HTML片段渲染
|
|
115
|
+
} else {
|
|
116
|
+
node.textContent = contentValue; // 纯文本渲染(防XSS)
|
|
117
|
+
}
|
|
74
118
|
});
|
|
75
|
-
}
|
|
119
|
+
});
|
|
76
120
|
|
|
77
|
-
|
|
121
|
+
// 渲染成功,打印友好提示
|
|
122
|
+
console.log('✅ XiangJsonCraft 渲染成功!样式+内容已全部加载');
|
|
78
123
|
})
|
|
79
|
-
.catch(
|
|
80
|
-
|
|
124
|
+
.catch((err) => {
|
|
125
|
+
// 捕获所有异步错误,统一处理
|
|
126
|
+
handleError(err.message);
|
|
81
127
|
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 兼容UMD打包:暴露全局变量,方便CDN引入调用
|
|
131
|
+
if (typeof window !== 'undefined') {
|
|
132
|
+
window.XiangJsonCraft = { renderJsonStyles };
|
|
82
133
|
}
|