项目架构调整,对组件进一步封装化
This commit is contained in:
parent
e571385d19
commit
5af0b3396e
@ -52,50 +52,14 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router';
|
||||
import { Setting, Document } from '@element-plus/icons-vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
// 导入已注册的小组件信息
|
||||
import { widgets as registeredWidgets } from '../widgets/registry';
|
||||
// 导入小组件显示信息
|
||||
import { getWidgetItems } from '../widgets/registry';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
// 定义小组件项的类型
|
||||
interface WidgetItem {
|
||||
value: string;
|
||||
label: string;
|
||||
icon: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const widgets = ref<WidgetItem[]>([]);
|
||||
|
||||
// 小组件图标映射
|
||||
const widgetIcons = {
|
||||
'clock': '⏰',
|
||||
'date': '📅',
|
||||
'text': '📝',
|
||||
'image': '🖼️',
|
||||
// 可以为其他小组件添加图标
|
||||
};
|
||||
|
||||
// 小组件描述映射
|
||||
const widgetDescriptions = {
|
||||
'clock': '显示当前时间,可自定义格式、样式和特效',
|
||||
'date': '显示当前日期,可自定义格式、样式和特效',
|
||||
'text': '显示文本,支持渐变、阴影、字体等自定义样式',
|
||||
'image': '显示图片,可自定义大小、特效和位置',
|
||||
// 可以为其他小组件添加描述
|
||||
};
|
||||
|
||||
// 初始化时加载小组件
|
||||
onMounted(() => {
|
||||
widgets.value = registeredWidgets.map((widget: any) => ({
|
||||
value: widget.value as string,
|
||||
label: widget.label as string,
|
||||
icon: widgetIcons[widget.value as keyof typeof widgetIcons] || '🔧', // 默认图标
|
||||
description: widgetDescriptions[widget.value as keyof typeof widgetDescriptions] || '自定义小组件'
|
||||
}));
|
||||
});
|
||||
// 获取所有可用的小组件列表
|
||||
const widgets = getWidgetItems();
|
||||
|
||||
const goToConfig = () => {
|
||||
router.push('/config');
|
||||
|
184
src/widgets/TEMPLATE.md
Normal file
184
src/widgets/TEMPLATE.md
Normal file
@ -0,0 +1,184 @@
|
||||
# 新建小组件模板
|
||||
|
||||
这是一个模板,用于快速创建新的小组件。
|
||||
|
||||
## 步骤
|
||||
|
||||
### 1. 创建小组件目录结构
|
||||
|
||||
```
|
||||
src/widgets/[widget-name]/
|
||||
├── index.ts # 小组件注册入口
|
||||
├── types.ts # 类型定义和默认配置
|
||||
├── Widget.vue # 小组件显示组件
|
||||
└── Config.vue # 小组件配置组件
|
||||
```
|
||||
|
||||
### 2. 实现 types.ts
|
||||
|
||||
```typescript
|
||||
import type { BaseWidgetConfig } from '../types';
|
||||
|
||||
// 小组件配置接口
|
||||
export interface YourWidgetConfig extends BaseWidgetConfig {
|
||||
// 定义你的配置属性
|
||||
text: string;
|
||||
color: string;
|
||||
fontSize: number;
|
||||
// ... 其他配置
|
||||
}
|
||||
|
||||
// 默认配置
|
||||
export const defaultConfig: YourWidgetConfig = {
|
||||
text: 'Hello World',
|
||||
color: '#ffffff',
|
||||
fontSize: 24,
|
||||
// ... 其他默认值
|
||||
};
|
||||
```
|
||||
|
||||
### 3. 实现 Widget.vue
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="your-widget" :style="widgetStyle">
|
||||
{{ config.text }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import type { YourWidgetConfig } from './types';
|
||||
|
||||
// 接收配置props
|
||||
const props = defineProps<{
|
||||
config: YourWidgetConfig;
|
||||
}>();
|
||||
|
||||
// 计算样式
|
||||
const widgetStyle = computed(() => ({
|
||||
color: props.config.color,
|
||||
fontSize: props.config.fontSize + 'px',
|
||||
// ... 其他样式
|
||||
}));
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.your-widget {
|
||||
/* 基础样式 */
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### 4. 实现 Config.vue
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="config-panel">
|
||||
<el-form :model="config" label-width="120px">
|
||||
<el-form-item label="文本内容">
|
||||
<el-input v-model="config.text" @input="updateConfig" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="文字颜色">
|
||||
<el-color-picker v-model="config.color" @change="updateConfig" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="字体大小">
|
||||
<el-slider
|
||||
v-model="config.fontSize"
|
||||
:min="12"
|
||||
:max="72"
|
||||
@change="updateConfig"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 其他配置项... -->
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, watch } from 'vue';
|
||||
import type { YourWidgetConfig } from './types';
|
||||
|
||||
// 接收配置和更新函数
|
||||
const props = defineProps<{
|
||||
modelValue: YourWidgetConfig;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [config: YourWidgetConfig];
|
||||
}>();
|
||||
|
||||
// 本地配置状态
|
||||
const config = reactive({ ...props.modelValue });
|
||||
|
||||
// 监听外部配置变化
|
||||
watch(() => props.modelValue, (newValue) => {
|
||||
Object.assign(config, newValue);
|
||||
}, { deep: true });
|
||||
|
||||
// 更新配置
|
||||
const updateConfig = () => {
|
||||
emit('update:modelValue', { ...config });
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.config-panel {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### 5. 实现 index.ts
|
||||
|
||||
```typescript
|
||||
import Widget from './Widget.vue';
|
||||
import Config from './Config.vue';
|
||||
import { defaultConfig } from './types';
|
||||
import { createWidget } from '../createWidget';
|
||||
|
||||
export default createWidget({
|
||||
label: '你的小组件',
|
||||
value: 'your-widget',
|
||||
icon: '🎯', // 选择合适的emoji图标
|
||||
description: '这是你的小组件的描述',
|
||||
component: Widget,
|
||||
configComponent: Config,
|
||||
defaultConfig
|
||||
});
|
||||
```
|
||||
|
||||
### 6. 在 registry.ts 中注册
|
||||
|
||||
```typescript
|
||||
// 在 src/widgets/registry.ts 中添加导入
|
||||
import YourWidget from './your-widget';
|
||||
|
||||
// 在小组件注册表中添加
|
||||
export const widgets: WidgetRegistration[] = [
|
||||
ClockWidget,
|
||||
DateWidget,
|
||||
TextWidget,
|
||||
ImageWidget,
|
||||
WeatherWidget,
|
||||
YourWidget, // 添加你的小组件
|
||||
];
|
||||
```
|
||||
|
||||
## 完成!
|
||||
|
||||
现在你的新小组件就会自动出现在:
|
||||
- 首页的小组件列表中
|
||||
- 配置页面的小组件选择器中
|
||||
- 预览页面中可以显示
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **命名规范**: 使用kebab-case命名目录和文件
|
||||
2. **图标选择**: 选择有意义的emoji作为图标
|
||||
3. **配置项**: 提供合理的默认值,让小组件开箱即用
|
||||
4. **样式**: 使用CSS变量和计算属性,让样式可配置
|
||||
5. **类型安全**: 充分利用TypeScript的类型检查
|
@ -1,11 +1,14 @@
|
||||
import Widget from './Widget.vue';
|
||||
import Config from './Config.vue';
|
||||
import { defaultConfig } from './types';
|
||||
import { createWidget } from '../createWidget';
|
||||
|
||||
export default {
|
||||
export default createWidget({
|
||||
label: '时钟小组件',
|
||||
value: 'clock',
|
||||
icon: '⏰',
|
||||
description: '显示当前时间,可自定义格式、样式和特效',
|
||||
component: Widget,
|
||||
configComponent: Config,
|
||||
getDefaultConfig: () => defaultConfig
|
||||
};
|
||||
defaultConfig
|
||||
});
|
||||
|
47
src/widgets/createWidget.ts
Normal file
47
src/widgets/createWidget.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import type { Component } from 'vue';
|
||||
import type { WidgetRegistration, BaseWidgetConfig } from './types';
|
||||
|
||||
/**
|
||||
* 创建小组件注册信息的辅助函数
|
||||
*
|
||||
* @param options 小组件配置选项
|
||||
* @returns 小组件注册信息
|
||||
*/
|
||||
export function createWidget(options: {
|
||||
/** 小组件显示名称 */
|
||||
label: string;
|
||||
/** 小组件唯一标识符 */
|
||||
value: string;
|
||||
/** 小组件图标(emoji 或图标字符) */
|
||||
icon: string;
|
||||
/** 小组件描述 */
|
||||
description: string;
|
||||
/** 小组件组件 */
|
||||
component: Component;
|
||||
/** 小组件配置组件 */
|
||||
configComponent: Component;
|
||||
/** 默认配置 */
|
||||
defaultConfig: BaseWidgetConfig;
|
||||
}): WidgetRegistration {
|
||||
return {
|
||||
label: options.label,
|
||||
value: options.value,
|
||||
icon: options.icon,
|
||||
description: options.description,
|
||||
component: options.component,
|
||||
configComponent: options.configComponent,
|
||||
getDefaultConfig: () => options.defaultConfig
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建小组件类型定义的辅助函数
|
||||
*
|
||||
* @param defaultConfig 默认配置对象
|
||||
* @returns 包含默认配置的对象
|
||||
*/
|
||||
export function createWidgetConfig<T extends BaseWidgetConfig>(defaultConfig: T) {
|
||||
return {
|
||||
defaultConfig
|
||||
};
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
import Widget from './Widget.vue';
|
||||
import Config from './Config.vue';
|
||||
import { defaultConfig } from './types';
|
||||
import { createWidget } from '../createWidget';
|
||||
|
||||
export default {
|
||||
export default createWidget({
|
||||
label: '日期小组件',
|
||||
value: 'date',
|
||||
icon: '📅',
|
||||
description: '显示当前日期,可自定义格式、样式和特效',
|
||||
component: Widget,
|
||||
configComponent: Config,
|
||||
getDefaultConfig: () => defaultConfig
|
||||
};
|
||||
defaultConfig
|
||||
});
|
||||
|
@ -1,11 +1,14 @@
|
||||
import Widget from './Widget.vue';
|
||||
import Config from './Config.vue';
|
||||
import { defaultConfig } from './types';
|
||||
import { createWidget } from '../createWidget';
|
||||
|
||||
export default {
|
||||
export default createWidget({
|
||||
label: '图片小组件',
|
||||
value: 'image',
|
||||
icon: '🖼️',
|
||||
description: '显示图片,可自定义大小、特效和位置',
|
||||
component: Widget,
|
||||
configComponent: Config,
|
||||
getDefaultConfig: () => defaultConfig
|
||||
};
|
||||
defaultConfig
|
||||
});
|
||||
|
@ -4,14 +4,28 @@ import DateWidget from './date';
|
||||
import TextWidget from './text';
|
||||
import ImageWidget from './image';
|
||||
|
||||
|
||||
// 导入类型定义
|
||||
import type { WidgetRegistration, WidgetItem } from './types';
|
||||
|
||||
// 小组件注册表
|
||||
export const widgets = [
|
||||
export const widgets: WidgetRegistration[] = [
|
||||
ClockWidget,
|
||||
DateWidget,
|
||||
TextWidget,
|
||||
ImageWidget,
|
||||
];
|
||||
|
||||
// 获取小组件显示信息列表(用于 UI 展示)
|
||||
export const getWidgetItems = (): WidgetItem[] => {
|
||||
return widgets.map(widget => ({
|
||||
value: widget.value,
|
||||
label: widget.label,
|
||||
icon: widget.icon,
|
||||
description: widget.description
|
||||
}));
|
||||
};
|
||||
|
||||
// 获取小组件默认配置
|
||||
export const getDefaultConfig = (widgetType: string) => {
|
||||
for (const widget of widgets) {
|
||||
@ -21,3 +35,8 @@ export const getDefaultConfig = (widgetType: string) => {
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
// 根据类型获取小组件注册信息
|
||||
export const getWidget = (widgetType: string): WidgetRegistration | undefined => {
|
||||
return widgets.find(widget => widget.value === widgetType);
|
||||
};
|
||||
|
@ -1,11 +1,14 @@
|
||||
import Widget from './Widget.vue';
|
||||
import Config from './Config.vue';
|
||||
import { defaultConfig } from './types';
|
||||
import { createWidget } from '../createWidget';
|
||||
|
||||
export default {
|
||||
export default createWidget({
|
||||
label: '文本小组件',
|
||||
value: 'text',
|
||||
icon: '📝',
|
||||
description: '显示文本,支持渐变、阴影、字体等自定义样式',
|
||||
component: Widget,
|
||||
configComponent: Config,
|
||||
getDefaultConfig: () => defaultConfig
|
||||
};
|
||||
defaultConfig
|
||||
});
|
||||
|
@ -9,12 +9,17 @@ export interface BaseWidgetConfig {
|
||||
export interface WidgetRegistration {
|
||||
label: string;
|
||||
value: string;
|
||||
icon: string;
|
||||
description: string;
|
||||
component: Component;
|
||||
configComponent: Component;
|
||||
getDefaultConfig: () => BaseWidgetConfig;
|
||||
}
|
||||
|
||||
// 小组件模块导出接口
|
||||
export interface WidgetModule {
|
||||
registration: WidgetRegistration;
|
||||
// 小组件列表项接口(用于 UI 显示)
|
||||
export interface WidgetItem {
|
||||
value: string;
|
||||
label: string;
|
||||
icon: string;
|
||||
description: string;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user