py-test-component 2.0.5 → 2.0.6
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/package.json +3 -9
- package/src/index.js +38 -0
- package/DEVELOPER.md +0 -541
- package/USAGE.md +0 -366
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "py-test-component",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "Vue2 + ElementUI 组件库,支持 React 使用",
|
|
5
5
|
"main": "dist/py-component.js",
|
|
6
6
|
"module": "dist/py-component.esm.js",
|
|
@@ -20,14 +20,8 @@
|
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
22
|
"dist",
|
|
23
|
-
"src
|
|
24
|
-
"
|
|
25
|
-
"src/store",
|
|
26
|
-
"src/utils",
|
|
27
|
-
"README.md",
|
|
28
|
-
"USAGE.md",
|
|
29
|
-
"DEVELOPER.md",
|
|
30
|
-
"src/vue"
|
|
23
|
+
"src",
|
|
24
|
+
"README.md"
|
|
31
25
|
],
|
|
32
26
|
"scripts": {
|
|
33
27
|
"build": "webpack --mode production",
|
package/src/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import Vue from 'vue';
|
|
2
|
+
import ElementUI from 'element-ui';
|
|
3
|
+
import 'element-ui/lib/theme-chalk/index.css';
|
|
4
|
+
import vueCustomElement from 'vue-custom-element';
|
|
5
|
+
|
|
6
|
+
import PyTable from './components/PyTable.vue';
|
|
7
|
+
import PyWeather from './components/PyWeather.vue';
|
|
8
|
+
import store from './store';
|
|
9
|
+
|
|
10
|
+
Vue.use(ElementUI);
|
|
11
|
+
Vue.use(vueCustomElement);
|
|
12
|
+
|
|
13
|
+
// 使用 vue-custom-element 创建 Web Components(禁用 Shadow DOM)
|
|
14
|
+
Vue.customElement('py-table', PyTable, {
|
|
15
|
+
shadow: false,
|
|
16
|
+
props: {
|
|
17
|
+
propData: {
|
|
18
|
+
default: null
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
Vue.customElement('py-weather', PyWeather, {
|
|
24
|
+
shadow: false
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// 初始化 store(唯一暴露给外部的 store 方法)
|
|
28
|
+
function initStore(config = {}) {
|
|
29
|
+
store.set(config);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 导出
|
|
33
|
+
export { PyTable, PyWeather, initStore };
|
|
34
|
+
export default { initStore };
|
|
35
|
+
|
|
36
|
+
if (typeof window !== 'undefined') {
|
|
37
|
+
window.PyComponent = { initStore };
|
|
38
|
+
}
|
package/DEVELOPER.md
DELETED
|
@@ -1,541 +0,0 @@
|
|
|
1
|
-
# PyComponent 组件库开发指南
|
|
2
|
-
|
|
3
|
-
本文档面向 AI 模型和开发者,指导如何开发、维护和扩展 `py-test-component` 组件库。
|
|
4
|
-
|
|
5
|
-
## 目录
|
|
6
|
-
|
|
7
|
-
1. [架构概述](#架构概述)
|
|
8
|
-
2. [核心原理](#核心原理)
|
|
9
|
-
3. [目录结构](#目录结构)
|
|
10
|
-
4. [添加新组件步骤](#添加新组件步骤)
|
|
11
|
-
5. [代码规范](#代码规范)
|
|
12
|
-
6. [构建流程](#构建流程)
|
|
13
|
-
7. [常见问题](#常见问题)
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## 架构概述
|
|
18
|
-
|
|
19
|
-
### 设计目标
|
|
20
|
-
|
|
21
|
-
- **跨框架**:Vue 2 组件可被 React 使用
|
|
22
|
-
- **零配置**:React 用户无需安装 Vue 和 ElementUI
|
|
23
|
-
- **单一入口**:所有组件统一使用 `propData` 接收参数
|
|
24
|
-
- **状态隔离**:组件库内部 store 不暴露给外部
|
|
25
|
-
|
|
26
|
-
### 技术栈
|
|
27
|
-
|
|
28
|
-
| 技术 | 用途 |
|
|
29
|
-
|------|------|
|
|
30
|
-
| Vue 2.7 | 组件开发框架 |
|
|
31
|
-
| ElementUI 2.15 | UI 组件库 |
|
|
32
|
-
| vue-custom-element | Vue 组件转 Web Components |
|
|
33
|
-
| Webpack 5 | 构建工具 |
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## 核心原理
|
|
38
|
-
|
|
39
|
-
### 1. Web Components 转换
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
Vue 组件 --[vue-custom-element]--> 自定义元素 --[React 包装器]--> React 组件
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
**关键点**:
|
|
46
|
-
- `src/index.js` 使用 `Vue.customElement()` 将 Vue 组件注册为 Web Components
|
|
47
|
-
- Shadow DOM 必须禁用(`shadow: false`),否则 ElementUI 样式无法穿透
|
|
48
|
-
|
|
49
|
-
### 2. React 适配机制
|
|
50
|
-
|
|
51
|
-
```javascript
|
|
52
|
-
// src/react/index.js
|
|
53
|
-
function wrapVueComponent(tagName, dataProp) {
|
|
54
|
-
return forwardRef(function WrappedComponent({ propData, loading, ...props }, ref) {
|
|
55
|
-
// 1. 动态加载组件库构建产物
|
|
56
|
-
// 2. 自动注入 ElementUI CSS
|
|
57
|
-
// 3. 将 propData 设置到自定义元素的 property
|
|
58
|
-
return <tagName ref={ref} {...props} />;
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
**关键点**:
|
|
64
|
-
- React 通过动态 `import()` 加载 `dist/py-component.esm.js`
|
|
65
|
-
- 数据通过直接设置 DOM property(而非 attribute)传递,避免 JSON 序列化
|
|
66
|
-
|
|
67
|
-
### 3. Store 隔离设计
|
|
68
|
-
|
|
69
|
-
```
|
|
70
|
-
外部工程 --[initStore]--> 组件库内部 store
|
|
71
|
-
|
|
72
|
-
外部无法:
|
|
73
|
-
- 读取 store 状态
|
|
74
|
-
- 订阅 store 变化
|
|
75
|
-
- 获取 store 实例
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
**实现方式**:
|
|
79
|
-
- `initStore()` 只接受配置对象,不返回任何可操作对象
|
|
80
|
-
- React 版本中 `initStore` 返回 `Promise<void>`,而非 store 实例
|
|
81
|
-
- `window.PyComponent` 仅暴露 `initStore` 方法
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## 目录结构
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
py-component/
|
|
89
|
-
├── dist/ # 构建产物(自动生成)
|
|
90
|
-
│ ├── py-component.js # UMD 格式
|
|
91
|
-
│ └── py-component.esm.js # ESM 格式
|
|
92
|
-
│
|
|
93
|
-
├── src/
|
|
94
|
-
│ ├── components/ # Vue 组件源码
|
|
95
|
-
│ │ ├── PyTable.vue
|
|
96
|
-
│ │ └── PyWeather.vue
|
|
97
|
-
│ │
|
|
98
|
-
│ ├── react/ # React 适配器
|
|
99
|
-
│ │ └── index.js # 组件包装器 + initStore
|
|
100
|
-
│ │
|
|
101
|
-
│ ├── vue/ # Vue 入口
|
|
102
|
-
│ │ └── index.js # 直接导出 Vue 组件
|
|
103
|
-
│ │
|
|
104
|
-
│ ├── store/ # 全局状态(内部使用)
|
|
105
|
-
│ │ └── index.js # Vue.observable + get/set/subscribe
|
|
106
|
-
│ │
|
|
107
|
-
│ ├── utils/ # 工具函数
|
|
108
|
-
│ │ ├── request.js # fetch 封装
|
|
109
|
-
│ │ └── api.js # API 请求封装
|
|
110
|
-
│ │
|
|
111
|
-
│ └── index.js # 主入口
|
|
112
|
-
│ # - 注册 Web Components
|
|
113
|
-
│ # - 导出 initStore
|
|
114
|
-
│ # - 挂载到 window.PyComponent
|
|
115
|
-
│
|
|
116
|
-
├── package.json
|
|
117
|
-
├── webpack.config.js # 双格式构建配置
|
|
118
|
-
├── README.md # 用户文档
|
|
119
|
-
├── USAGE.md # 使用教程
|
|
120
|
-
└── DEVELOPER.md # 本文件
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## 添加新组件步骤
|
|
126
|
-
|
|
127
|
-
### 步骤 1:创建 Vue 组件
|
|
128
|
-
|
|
129
|
-
**文件**:`src/components/PyNewComponent.vue`
|
|
130
|
-
|
|
131
|
-
```vue
|
|
132
|
-
<template>
|
|
133
|
-
<div class="py-new-component">
|
|
134
|
-
<!-- 使用 ElementUI 组件 -->
|
|
135
|
-
<el-input v-model="innerValue" />
|
|
136
|
-
</div>
|
|
137
|
-
</template>
|
|
138
|
-
|
|
139
|
-
<script>
|
|
140
|
-
// 从 store 获取配置(内部使用)
|
|
141
|
-
import store from '../store';
|
|
142
|
-
|
|
143
|
-
export default {
|
|
144
|
-
name: 'PyNewComponent',
|
|
145
|
-
|
|
146
|
-
// 统一使用 propData 接收外部数据
|
|
147
|
-
props: {
|
|
148
|
-
propData: {
|
|
149
|
-
default: null // 不限制类型
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
data() {
|
|
154
|
-
return {
|
|
155
|
-
innerValue: ''
|
|
156
|
-
};
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
computed: {
|
|
160
|
-
// 根据 propData 类型做适配
|
|
161
|
-
config() {
|
|
162
|
-
return this.propData || {};
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
|
|
166
|
-
mounted() {
|
|
167
|
-
// 读取 store 中的配置(内部使用)
|
|
168
|
-
const apiKey = store.get('apiKey');
|
|
169
|
-
console.log('apiKey:', apiKey);
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
methods: {
|
|
173
|
-
handleClick() {
|
|
174
|
-
// 触发事件供外部监听
|
|
175
|
-
this.$emit('change', this.innerValue);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
</script>
|
|
180
|
-
|
|
181
|
-
<style scoped>
|
|
182
|
-
.py-new-component {
|
|
183
|
-
padding: 20px;
|
|
184
|
-
}
|
|
185
|
-
</style>
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
**要点**:
|
|
189
|
-
- 组件名必须以 `Py` 开头
|
|
190
|
-
- 必须定义 `propData` prop,且不限制类型
|
|
191
|
-
- 使用 `scoped` 样式避免污染
|
|
192
|
-
|
|
193
|
-
### 步骤 2:注册 Web Component
|
|
194
|
-
|
|
195
|
-
**文件**:`src/index.js`
|
|
196
|
-
|
|
197
|
-
```javascript
|
|
198
|
-
import PyNewComponent from './components/PyNewComponent.vue';
|
|
199
|
-
|
|
200
|
-
// 注册为自定义元素
|
|
201
|
-
Vue.customElement('py-new-component', PyNewComponent, {
|
|
202
|
-
shadow: false // 必须禁用 Shadow DOM
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// 如有需要,在 window.PyComponent 中保持引用(可选)
|
|
206
|
-
if (typeof window !== 'undefined') {
|
|
207
|
-
window.PyComponent = {
|
|
208
|
-
initStore,
|
|
209
|
-
// 不暴露 store 实例
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### 步骤 3:Vue 入口导出
|
|
215
|
-
|
|
216
|
-
**文件**:`src/vue/index.js`
|
|
217
|
-
|
|
218
|
-
```javascript
|
|
219
|
-
import PyNewComponent from '../components/PyNewComponent.vue';
|
|
220
|
-
|
|
221
|
-
export { PyTable, PyWeather, PyNewComponent, initStore };
|
|
222
|
-
export default { PyTable, PyWeather, PyNewComponent, initStore };
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### 步骤 4:React 入口导出
|
|
226
|
-
|
|
227
|
-
**文件**:`src/react/index.js`
|
|
228
|
-
|
|
229
|
-
```javascript
|
|
230
|
-
// 在已有组件后添加
|
|
231
|
-
export const PyNewComponent = wrapVueComponent('py-new-component', 'propData');
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
**参数说明**:
|
|
235
|
-
- 第一个参数:自定义元素标签名(必须与 `Vue.customElement` 注册时一致)
|
|
236
|
-
- 第二个参数:数据 property 名(统一为 `'propData'`)
|
|
237
|
-
|
|
238
|
-
### 步骤 5:构建验证
|
|
239
|
-
|
|
240
|
-
```bash
|
|
241
|
-
npm run build
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
检查 `dist/` 目录下是否生成新的构建产物。
|
|
245
|
-
|
|
246
|
-
### 步骤 6:更新文档
|
|
247
|
-
|
|
248
|
-
- `README.md`:组件列表中添加新组件
|
|
249
|
-
- `USAGE.md`:添加新组件的参数说明和使用示例
|
|
250
|
-
|
|
251
|
-
---
|
|
252
|
-
|
|
253
|
-
## 代码规范
|
|
254
|
-
|
|
255
|
-
### 1. 组件命名
|
|
256
|
-
|
|
257
|
-
```
|
|
258
|
-
Py + PascalCase
|
|
259
|
-
|
|
260
|
-
✅ PyTable
|
|
261
|
-
✅ PyWeather
|
|
262
|
-
✅ PyUserForm
|
|
263
|
-
|
|
264
|
-
❌ py-table (Vue 组件名用大驼峰)
|
|
265
|
-
❌ PYTABLE (不要全大写)
|
|
266
|
-
❌ NewComponent (缺少 Py 前缀)
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### 2. Props 规范
|
|
270
|
-
|
|
271
|
-
```javascript
|
|
272
|
-
// ✅ 正确:统一使用 propData
|
|
273
|
-
props: {
|
|
274
|
-
propData: {
|
|
275
|
-
default: null // 不限制类型,灵活使用
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// ❌ 错误:不要使用多个 props
|
|
280
|
-
props: {
|
|
281
|
-
data: Array,
|
|
282
|
-
config: Object,
|
|
283
|
-
value: String
|
|
284
|
-
}
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
### 3. Store 使用规范
|
|
288
|
-
|
|
289
|
-
```javascript
|
|
290
|
-
// ✅ 正确:组件内部读取 store
|
|
291
|
-
import store from '../store';
|
|
292
|
-
|
|
293
|
-
export default {
|
|
294
|
-
mounted() {
|
|
295
|
-
const config = store.get('apiKey'); // 读取
|
|
296
|
-
},
|
|
297
|
-
methods: {
|
|
298
|
-
update() {
|
|
299
|
-
store.set('key', value); // 内部组件也可以设置
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
// ❌ 错误:不要在外部暴露 store
|
|
305
|
-
export { store }; // 禁止!
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
### 4. CSS 规范
|
|
309
|
-
|
|
310
|
-
```vue
|
|
311
|
-
<style scoped>
|
|
312
|
-
/* ✅ 使用 scoped */
|
|
313
|
-
.py-component-name {
|
|
314
|
-
/* 组件名作为前缀 */
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/* ❌ 不要污染全局 */
|
|
318
|
-
.el-input {
|
|
319
|
-
/* 这会覆盖 ElementUI 默认样式 */
|
|
320
|
-
}
|
|
321
|
-
</style>
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### 5. 事件规范
|
|
325
|
-
|
|
326
|
-
```javascript
|
|
327
|
-
// ✅ 使用自定义事件与外部通信
|
|
328
|
-
this.$emit('change', value);
|
|
329
|
-
this.$emit('submit', formData);
|
|
330
|
-
|
|
331
|
-
// ❌ 不要直接操作外部状态
|
|
332
|
-
externalStore.data = value; // 禁止!
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
---
|
|
336
|
-
|
|
337
|
-
## 构建流程
|
|
338
|
-
|
|
339
|
-
### 开发模式
|
|
340
|
-
|
|
341
|
-
```bash
|
|
342
|
-
npm run dev
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
- Webpack 监听文件变化
|
|
346
|
-
- 自动重新构建到 `dist/`
|
|
347
|
-
- 不压缩,便于调试
|
|
348
|
-
|
|
349
|
-
### 生产构建
|
|
350
|
-
|
|
351
|
-
```bash
|
|
352
|
-
npm run build
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
- 生成两种格式:
|
|
356
|
-
- `py-component.js`(UMD,浏览器直接使用)
|
|
357
|
-
- `py-component.esm.js`(ESM,构建工具使用)
|
|
358
|
-
- 代码压缩,体积优化
|
|
359
|
-
|
|
360
|
-
### 构建配置要点
|
|
361
|
-
|
|
362
|
-
**`webpack.config.js`**:
|
|
363
|
-
|
|
364
|
-
```javascript
|
|
365
|
-
// 关键配置
|
|
366
|
-
const baseConfig = {
|
|
367
|
-
module: {
|
|
368
|
-
rules: [
|
|
369
|
-
{ test: /\.vue$/, loader: 'vue-loader' },
|
|
370
|
-
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }
|
|
371
|
-
]
|
|
372
|
-
},
|
|
373
|
-
resolve: {
|
|
374
|
-
alias: {
|
|
375
|
-
'vue$': 'vue/dist/vue.esm.js' // 使用完整版 Vue
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
---
|
|
382
|
-
|
|
383
|
-
## 常见问题
|
|
384
|
-
|
|
385
|
-
### Q1: React 中组件不显示
|
|
386
|
-
|
|
387
|
-
**排查步骤**:
|
|
388
|
-
1. 检查 `dist/py-component.esm.js` 是否存在
|
|
389
|
-
2. 检查浏览器控制台是否有加载错误
|
|
390
|
-
3. 确认 CSS 是否已注入(`<link>` 标签是否出现在 `<head>`)
|
|
391
|
-
4. 检查 `propData` 是否正确设置到 DOM property
|
|
392
|
-
|
|
393
|
-
### Q2: ElementUI 样式不生效
|
|
394
|
-
|
|
395
|
-
**原因**:Shadow DOM 隔离了样式
|
|
396
|
-
**解决**:确保 `shadow: false`
|
|
397
|
-
|
|
398
|
-
```javascript
|
|
399
|
-
Vue.customElement('py-component', Component, {
|
|
400
|
-
shadow: false // 必须
|
|
401
|
-
});
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
### Q3: propData 传递后不更新
|
|
405
|
-
|
|
406
|
-
**原因**:通过 attribute 传递了对象/数组,导致序列化问题
|
|
407
|
-
**解决**:使用 DOM property 而非 attribute
|
|
408
|
-
|
|
409
|
-
```javascript
|
|
410
|
-
// ✅ 正确:直接设置 property
|
|
411
|
-
elRef.current.propData = data;
|
|
412
|
-
|
|
413
|
-
// ❌ 错误:通过 attribute(会导致 JSON 序列化)
|
|
414
|
-
elRef.current.setAttribute('propData', JSON.stringify(data));
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
### Q4: store 数据在 React 中无法响应
|
|
418
|
-
|
|
419
|
-
**原因**:Vue.observable 与 React 响应式系统不兼容
|
|
420
|
-
**设计如此**:store 完全内部化,React 只能设置不能读取
|
|
421
|
-
**替代方案**:通过组件事件与外部通信
|
|
422
|
-
|
|
423
|
-
```javascript
|
|
424
|
-
// Vue 组件内
|
|
425
|
-
this.$emit('update', newValue);
|
|
426
|
-
|
|
427
|
-
// React 中使用
|
|
428
|
-
<PyComponent onUpdate={(e) => console.log(e.detail)} />
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
### Q5: 如何调试 Web Component
|
|
432
|
-
|
|
433
|
-
**浏览器控制台**:
|
|
434
|
-
|
|
435
|
-
```javascript
|
|
436
|
-
// 查看已注册的自定义元素
|
|
437
|
-
customElements.get('py-table');
|
|
438
|
-
|
|
439
|
-
// 获取组件实例(Vue 内部)
|
|
440
|
-
document.querySelector('py-table').__vue__;
|
|
441
|
-
|
|
442
|
-
// 手动设置数据
|
|
443
|
-
document.querySelector('py-table').propData = [...];
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
---
|
|
447
|
-
|
|
448
|
-
## 扩展建议
|
|
449
|
-
|
|
450
|
-
### 添加 TypeScript 支持
|
|
451
|
-
|
|
452
|
-
如需支持 TypeScript:
|
|
453
|
-
|
|
454
|
-
1. 创建 `index.d.ts`:
|
|
455
|
-
|
|
456
|
-
```typescript
|
|
457
|
-
declare module 'py-test-component' {
|
|
458
|
-
export function initStore(config: Record<string, any>): void;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
declare module 'py-test-component/vue' {
|
|
462
|
-
import { Component } from 'vue';
|
|
463
|
-
export const PyTable: Component;
|
|
464
|
-
export const PyWeather: Component;
|
|
465
|
-
export function initStore(config: Record<string, any>): void;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
declare module 'py-test-component/react' {
|
|
469
|
-
import { ForwardRefExoticComponent, RefAttributes } from 'react';
|
|
470
|
-
|
|
471
|
-
interface PyComponentProps {
|
|
472
|
-
propData?: any;
|
|
473
|
-
loading?: React.ReactNode;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
export const PyTable: ForwardRefExoticComponent<PyComponentProps & RefAttributes<any>>;
|
|
477
|
-
export const PyWeather: ForwardRefExoticComponent<PyComponentProps & RefAttributes<any>>;
|
|
478
|
-
export function initStore(config: Record<string, any>): Promise<void>;
|
|
479
|
-
}
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
2. 在 `package.json` 中添加:
|
|
483
|
-
|
|
484
|
-
```json
|
|
485
|
-
{
|
|
486
|
-
"types": "index.d.ts"
|
|
487
|
-
}
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
### 优化构建体积
|
|
491
|
-
|
|
492
|
-
当前构建产物包含完整 Vue 和 ElementUI(约 1.1MB)。如需优化:
|
|
493
|
-
|
|
494
|
-
1. **按需加载 ElementUI 组件**:
|
|
495
|
-
|
|
496
|
-
```javascript
|
|
497
|
-
// 不使用完整导入
|
|
498
|
-
// import ElementUI from 'element-ui'; // 太大
|
|
499
|
-
|
|
500
|
-
// 改为按需导入
|
|
501
|
-
import { Table, TableColumn } from 'element-ui';
|
|
502
|
-
Vue.use(Table);
|
|
503
|
-
Vue.use(TableColumn);
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
2. **配置 Externals**(如果外部工程已引入 Vue):
|
|
507
|
-
|
|
508
|
-
```javascript
|
|
509
|
-
// webpack.config.js
|
|
510
|
-
module.exports = {
|
|
511
|
-
externals: {
|
|
512
|
-
vue: 'Vue',
|
|
513
|
-
'element-ui': 'ELEMENT'
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
---
|
|
519
|
-
|
|
520
|
-
## 总结
|
|
521
|
-
|
|
522
|
-
开发新组件的核心流程:
|
|
523
|
-
|
|
524
|
-
1. **Vue 组件** → `src/components/PyXxx.vue`
|
|
525
|
-
2. **Web Component 注册** → `src/index.js`
|
|
526
|
-
3. **Vue 入口导出** → `src/vue/index.js`
|
|
527
|
-
4. **React 入口导出** → `src/react/index.js`
|
|
528
|
-
5. **构建验证** → `npm run build`
|
|
529
|
-
6. **更新文档** → `README.md` + `USAGE.md`
|
|
530
|
-
|
|
531
|
-
**必须遵守的原则**:
|
|
532
|
-
- ✅ 统一使用 `propData` 传递数据
|
|
533
|
-
- ✅ Store 完全内部化,外部只能设置
|
|
534
|
-
- ✅ Web Component 禁用 Shadow DOM
|
|
535
|
-
- ✅ 组件名以 `Py` 开头
|
|
536
|
-
|
|
537
|
-
---
|
|
538
|
-
|
|
539
|
-
**维护者备注**:
|
|
540
|
-
|
|
541
|
-
本文档应与代码同步更新。如修改了核心机制(如 store 设计、数据传递方式),必须同步更新本文档。
|
package/USAGE.md
DELETED
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
# 使用文档
|
|
2
|
-
|
|
3
|
-
本文档介绍如何在 Vue 和 React 项目中使用 `py-test-component` 组件库。
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Vue 项目使用
|
|
8
|
-
|
|
9
|
-
### 1. 安装
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm install py-test-component
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
### 2. 引入 ElementUI CSS
|
|
16
|
-
|
|
17
|
-
在入口文件(如 `main.js`)中引入 ElementUI 样式:
|
|
18
|
-
|
|
19
|
-
```javascript
|
|
20
|
-
import Vue from 'vue';
|
|
21
|
-
import 'element-ui/lib/theme-chalk/index.css'; // 必须引入
|
|
22
|
-
import { initStore } from 'py-test-component';
|
|
23
|
-
|
|
24
|
-
// 初始化组件库配置(仅设置,配置仅供组件库内部使用)
|
|
25
|
-
initStore({
|
|
26
|
-
apiKey: 'your-api-key',
|
|
27
|
-
baseUrl: 'https://api.example.com'
|
|
28
|
-
});
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
**注意**:`initStore` 只能设置配置,无法读取 store 状态,避免与外部工程的状态管理冲突。
|
|
32
|
-
|
|
33
|
-
### 3. 使用组件
|
|
34
|
-
|
|
35
|
-
#### 方式一:按需导入组件
|
|
36
|
-
|
|
37
|
-
```vue
|
|
38
|
-
<template>
|
|
39
|
-
<div>
|
|
40
|
-
<PyTable :propData="tableData" />
|
|
41
|
-
<PyWeather />
|
|
42
|
-
</div>
|
|
43
|
-
</template>
|
|
44
|
-
|
|
45
|
-
<script>
|
|
46
|
-
import { PyTable, PyWeather } from 'py-test-component/vue';
|
|
47
|
-
|
|
48
|
-
export default {
|
|
49
|
-
components: {
|
|
50
|
-
PyTable,
|
|
51
|
-
PyWeather
|
|
52
|
-
},
|
|
53
|
-
data() {
|
|
54
|
-
return {
|
|
55
|
-
tableData: [
|
|
56
|
-
{ date: '2024-01-01', name: '张三', address: '北京市' },
|
|
57
|
-
{ date: '2024-01-02', name: '李四', address: '上海市' }
|
|
58
|
-
]
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
</script>
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
#### 方式二:全局注册
|
|
66
|
-
|
|
67
|
-
```javascript
|
|
68
|
-
// main.js
|
|
69
|
-
import { PyTable, PyWeather } from 'py-test-component/vue';
|
|
70
|
-
|
|
71
|
-
Vue.component('PyTable', PyTable);
|
|
72
|
-
Vue.component('PyWeather', PyWeather);
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### 4. 组件参数
|
|
76
|
-
|
|
77
|
-
#### PyTable
|
|
78
|
-
|
|
79
|
-
| 参数 | 类型 | 默认值 | 说明 |
|
|
80
|
-
|------|------|--------|------|
|
|
81
|
-
| propData | any | null | 表格数据,需为数组格式 |
|
|
82
|
-
|
|
83
|
-
```vue
|
|
84
|
-
<PyTable :propData="[
|
|
85
|
-
{ date: '2024-01-01', name: '张三', address: '北京' }
|
|
86
|
-
]" />
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
#### PyWeather
|
|
90
|
-
|
|
91
|
-
| 参数 | 类型 | 默认值 | 说明 |
|
|
92
|
-
|------|------|--------|------|
|
|
93
|
-
| propData | object | null | 可选配置,如 `{ city: '北京' }` |
|
|
94
|
-
|
|
95
|
-
```vue
|
|
96
|
-
<PyWeather :propData="{ city: '北京' }" />
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### 5. initStore 配置
|
|
100
|
-
|
|
101
|
-
```javascript
|
|
102
|
-
import { initStore } from 'py-test-component';
|
|
103
|
-
|
|
104
|
-
// 同步调用,仅设置配置到组件库内部 store
|
|
105
|
-
// 配置仅供组件库内部使用,外部无法读取
|
|
106
|
-
initStore({
|
|
107
|
-
apiKey: 'your-api-key',
|
|
108
|
-
baseUrl: 'https://api.example.com',
|
|
109
|
-
// 任意自定义配置
|
|
110
|
-
});
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
**重要**:`initStore` 只能写入配置,外部工程无法通过任何方式读取 store 状态,确保不会污染外部工程的状态管理。
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## React 项目使用
|
|
118
|
-
|
|
119
|
-
### 1. 安装
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
npm install py-test-component
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### 2. 初始化配置
|
|
126
|
-
|
|
127
|
-
在入口文件(如 `index.js`)中初始化:
|
|
128
|
-
|
|
129
|
-
```javascript
|
|
130
|
-
import React from 'react';
|
|
131
|
-
import ReactDOM from 'react-dom/client';
|
|
132
|
-
import { initStore } from 'py-test-component/react';
|
|
133
|
-
import App from './App';
|
|
134
|
-
|
|
135
|
-
// 异步初始化(返回 Promise,不返回 store)
|
|
136
|
-
initStore({
|
|
137
|
-
apiKey: 'your-api-key',
|
|
138
|
-
baseUrl: 'https://api.example.com'
|
|
139
|
-
}).then(() => {
|
|
140
|
-
console.log('组件库初始化完成');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// 或者使用 async/await
|
|
144
|
-
async function bootstrap() {
|
|
145
|
-
await initStore({ apiKey: 'xxx' });
|
|
146
|
-
|
|
147
|
-
const root = ReactDOM.createRoot(document.getElementById('root'));
|
|
148
|
-
root.render(<App />);
|
|
149
|
-
}
|
|
150
|
-
bootstrap();
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
**注意**:`initStore` 返回的 Promise 不会 resolve store 实例,仅表示初始化完成。
|
|
154
|
-
|
|
155
|
-
### 3. 使用组件
|
|
156
|
-
|
|
157
|
-
```jsx
|
|
158
|
-
import React, { useState } from 'react';
|
|
159
|
-
import { PyTable, PyWeather } from 'py-test-component/react';
|
|
160
|
-
|
|
161
|
-
function MyComponent() {
|
|
162
|
-
const [tableData] = useState([
|
|
163
|
-
{ date: '2024-01-01', name: '张三', address: '北京市' },
|
|
164
|
-
{ date: '2024-01-02', name: '李四', address: '上海市' }
|
|
165
|
-
]);
|
|
166
|
-
|
|
167
|
-
return (
|
|
168
|
-
<div>
|
|
169
|
-
<h1>React 中使用 Vue 组件</h1>
|
|
170
|
-
|
|
171
|
-
<section>
|
|
172
|
-
<h2>表格组件</h2>
|
|
173
|
-
<PyTable
|
|
174
|
-
propData={tableData}
|
|
175
|
-
loading={<div>加载中...</div>} // 可选:加载占位
|
|
176
|
-
/>
|
|
177
|
-
</section>
|
|
178
|
-
|
|
179
|
-
<section>
|
|
180
|
-
<h2>天气组件</h2>
|
|
181
|
-
<PyWeather loading={<div>加载中...</div>} />
|
|
182
|
-
</section>
|
|
183
|
-
</div>
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export default MyComponent;
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### 4. 组件参数
|
|
191
|
-
|
|
192
|
-
#### PyTable
|
|
193
|
-
|
|
194
|
-
| 参数 | 类型 | 默认值 | 说明 |
|
|
195
|
-
|------|------|--------|------|
|
|
196
|
-
| propData | any | undefined | 表格数据数组 |
|
|
197
|
-
| loading | ReactNode | undefined | 组件加载时的占位内容 |
|
|
198
|
-
|
|
199
|
-
```jsx
|
|
200
|
-
<PyTable
|
|
201
|
-
propData={[{ date: '2024-01-01', name: '张三' }]}
|
|
202
|
-
loading={<Spinner />}
|
|
203
|
-
/>
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
#### PyWeather
|
|
207
|
-
|
|
208
|
-
| 参数 | 类型 | 默认值 | 说明 |
|
|
209
|
-
|------|------|--------|------|
|
|
210
|
-
| propData | object | undefined | 可选配置对象 |
|
|
211
|
-
| loading | ReactNode | undefined | 组件加载时的占位内容 |
|
|
212
|
-
|
|
213
|
-
```jsx
|
|
214
|
-
<PyWeather
|
|
215
|
-
propData={{ city: '北京' }}
|
|
216
|
-
loading={<div>正在加载天气组件...</div>}
|
|
217
|
-
/>
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### 5. initStore 配置
|
|
221
|
-
|
|
222
|
-
```javascript
|
|
223
|
-
import { initStore } from 'py-test-component/react';
|
|
224
|
-
|
|
225
|
-
// 异步调用,仅设置配置到组件库内部 store
|
|
226
|
-
// 不返回 store 实例,外部无法读取
|
|
227
|
-
await initStore({
|
|
228
|
-
apiKey: 'your-api-key',
|
|
229
|
-
baseUrl: 'https://api.example.com'
|
|
230
|
-
});
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
**重要**:React 中的 `initStore` 是异步的,且不暴露任何 store 方法,配置仅供组件库内部使用。
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
## Store 使用原则
|
|
238
|
-
|
|
239
|
-
**组件库的 store 完全内部化**:
|
|
240
|
-
- ✅ 外部可以通过 `initStore` 设置配置
|
|
241
|
-
- ❌ 外部无法读取 store 状态
|
|
242
|
-
- ❌ 外部无法订阅 store 变化
|
|
243
|
-
- ❌ 外部无法获取 store 实例
|
|
244
|
-
|
|
245
|
-
**这样设计的好处**:
|
|
246
|
-
1. 避免与外部工程的状态管理(Vuex、Redux、MobX 等)冲突
|
|
247
|
-
2. 组件库内部可以自主管理状态
|
|
248
|
-
3. 外部工程只需关注传入配置,无需关心组件库内部状态
|
|
249
|
-
|
|
250
|
-
---
|
|
251
|
-
|
|
252
|
-
## 本地开发测试
|
|
253
|
-
|
|
254
|
-
### 使用 file: 协议引用本地包
|
|
255
|
-
|
|
256
|
-
在测试项目的 `package.json` 中:
|
|
257
|
-
|
|
258
|
-
```json
|
|
259
|
-
{
|
|
260
|
-
"dependencies": {
|
|
261
|
-
"py-test-component": "file:../py-component"
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
然后执行:
|
|
267
|
-
|
|
268
|
-
```bash
|
|
269
|
-
npm install
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
### 测试项目结构
|
|
273
|
-
|
|
274
|
-
```
|
|
275
|
-
my-vue2-components/
|
|
276
|
-
├── py-component/ # 组件库源码
|
|
277
|
-
├── vue-test/ # Vue 测试工程
|
|
278
|
-
└── react-test/ # React 测试工程
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
---
|
|
282
|
-
|
|
283
|
-
## 常见问题
|
|
284
|
-
|
|
285
|
-
### Q: React 项目中组件加载很慢?
|
|
286
|
-
|
|
287
|
-
A: 首次加载时需要动态下载和解析 `py-component.esm.js`(约 1.1MB)。建议:
|
|
288
|
-
- 在生产环境使用 CDN 加速
|
|
289
|
-
- 或预加载组件库:`initStore()` 提前调用
|
|
290
|
-
|
|
291
|
-
### Q: 样式不生效?
|
|
292
|
-
|
|
293
|
-
A:
|
|
294
|
-
- **Vue**: 确保引入了 `element-ui/lib/theme-chalk/index.css`
|
|
295
|
-
- **React**: CSS 会自动注入,无需手动引入
|
|
296
|
-
|
|
297
|
-
### Q: propData 可以传什么类型?
|
|
298
|
-
|
|
299
|
-
A: 不限制类型,可以是:
|
|
300
|
-
- 数组(PyTable 需要)
|
|
301
|
-
- 对象(配置项)
|
|
302
|
-
- 任意 JavaScript 值
|
|
303
|
-
|
|
304
|
-
### Q: 如何监听 store 变化?
|
|
305
|
-
|
|
306
|
-
A: **不支持**。store 完全内部化,外部无法监听。如需与外部通信,建议通过组件事件或回调函数。
|
|
307
|
-
|
|
308
|
-
### Q: 如何读取 store 中的配置?
|
|
309
|
-
|
|
310
|
-
A: **不支持**。store 仅供组件库内部使用,外部只能通过 `initStore` 设置,无法读取。
|
|
311
|
-
|
|
312
|
-
---
|
|
313
|
-
|
|
314
|
-
## 完整示例
|
|
315
|
-
|
|
316
|
-
### Vue 完整示例
|
|
317
|
-
|
|
318
|
-
```vue
|
|
319
|
-
<!-- App.vue -->
|
|
320
|
-
<template>
|
|
321
|
-
<div id="app">
|
|
322
|
-
<h1>Vue 使用 PyComponent</h1>
|
|
323
|
-
<PyTable :propData="users" />
|
|
324
|
-
<PyWeather />
|
|
325
|
-
</div>
|
|
326
|
-
</template>
|
|
327
|
-
|
|
328
|
-
<script>
|
|
329
|
-
import { PyTable, PyWeather } from 'py-test-component/vue';
|
|
330
|
-
|
|
331
|
-
export default {
|
|
332
|
-
components: { PyTable, PyWeather },
|
|
333
|
-
data() {
|
|
334
|
-
return {
|
|
335
|
-
users: [
|
|
336
|
-
{ date: '2024-01', name: '张三', address: '北京' },
|
|
337
|
-
{ date: '2024-02', name: '李四', address: '上海' }
|
|
338
|
-
]
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
</script>
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
### React 完整示例
|
|
346
|
-
|
|
347
|
-
```jsx
|
|
348
|
-
// App.jsx
|
|
349
|
-
import React, { useState } from 'react';
|
|
350
|
-
import { PyTable, PyWeather } from 'py-test-component/react';
|
|
351
|
-
|
|
352
|
-
export default function App() {
|
|
353
|
-
const [data] = useState([
|
|
354
|
-
{ date: '2024-01', name: '张三', address: '北京' },
|
|
355
|
-
{ date: '2024-02', name: '李四', address: '上海' }
|
|
356
|
-
]);
|
|
357
|
-
|
|
358
|
-
return (
|
|
359
|
-
<div>
|
|
360
|
-
<h1>React 使用 PyComponent</h1>
|
|
361
|
-
<PyTable propData={data} loading={<p>加载中...</p>} />
|
|
362
|
-
<PyWeather loading={<p>加载中...</p>} />
|
|
363
|
-
</div>
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
```
|