业务组件开发与上传指南
在前面的章节中,我们已经介绍了如何上传一个基础组件。然而,在企业实际开发场景中,我们通常需要开发和共享具有实际业务价值的组件。本文将详细介绍如何在 comp-hub 平台上开发和上传业务组件。
工程化环境下组件开发的挑战
在传统工程化环境中开发 Vue 组件时,通常需要考虑以下几个关键要素:
1. 组件依赖资源
- 静态资源:如图像、图标等通常存放在项目的
assets目录中 - 全局工具函数:如日期处理、数据转换等实用函数通常位于
utils目录
2. UI 库集成
- 现代前端开发普遍依赖 UI 组件库(如 Element UI、Ant Design Vue 等)
- 组件通常会复用这些 UI 库提供的基础组件
3. CSS 预处理器
- 开发中常使用 SCSS、Less 等预处理器提高样式开发效率
- 预处理器提供的变量、嵌套、混合等特性极大提升了样式代码的可维护性
4. 第三方依赖
- 组件可能需要引入专业库,如数据可视化库(ECharts)、日期处理库(dayjs)等
comp-hub 平台的组件规范
comp-hub 平台设计的目标是在保证组件可移植性的同时,尽可能保留开发者熟悉的开发体验。因此,除了基础组件上传规范外,业务组件还需要遵循以下特殊规范:
- 资源自包含:组件依赖的所有资源必须包含在组件文件夹内,且必须使用相对路径引用,不支持路径别名
- UI 库支持:目前平台仅支持 Element UI(Vue 2)和 Element Plus(Vue 3)
- UI 组件规范:使用 UI 库时,必须遵循官方推荐的组件使用规范,以便平台正确识别和适配
- CSS 预处理器:目前仅支持 SCSS 预处理器
开发业务组件实例
接下来,我们将按照平台规范开发一个具有实际业务价值的组件。我们选择开发一个日活率显示组件,这是数据可视化中常见的业务需求。
组件预览

这是一个基于 ECharts 开发的日活率显示组件,具有以下特点:
- 使用环形图展示数据比例
- 包含图例说明不同数据类别
- 中间显示核心指标数值
- 具有旋转背景动画效果
- 支持响应式调整大小
组件目录结构
遵循 comp-hub 规范的组件目录结构如下:
QinParamRatio/ # 组件根目录(名称即为组件名)
├── demo/ # 示例目录
│ ├── full.vue # 全屏预览示例
│ └── index.vue # 小窗预览示例
├── img/ # 图片资源目录
│ └── bg.png # 背景图片
├── comp.json # 组件配置文件(由平台自动生成)
├── index.vue # 组件入口文件
└── README.md # 组件文档组件实现代码
以下是 index.vue 的完整实现代码,包含模板、逻辑和样式:
vue
<template>
<figure class="ratio" :style="cssVar">
<!-- 图例 -->
<figcaption class="ratio__legend">
<span v-for="i in legend" :key="i.name" class="ratio__tag" :style="{ '--c': i.color }">{{ i.name }}</span>
</figcaption>
<!-- 旋转背景 -->
<img class="ratio__bg" :src="bgIcon" />
<!-- 中心文字 -->
<figcaption class="ratio__title">
<b>{{ title }}</b>
<em>{{ val }}</em>
</figcaption>
<!-- 图表容器 -->
<div ref="chart" class="ratio__chart"></div>
</figure>
</template>
<script>
// 导入第三方库
import * as echarts from "echarts";
// 使用相对路径导入图片资源
import bgIcon from './img/bg.png'
export default {
// 组件名称
name: 'QinParamRatio',
// 组件接收的属性
props: {
// 图例配置
legend: {
type: Array,
default: () => [
{ name: '注册用户1', color: '#082847' },
{ name: '日活用户1', color: '#0e8d5e' }
]
},
// 标题文本
title: { type: String, default: '日活率' },
// 核心数值
val: { type: Number, default: 100 },
// 组件尺寸
size: { type: Number, default: 250 }
},
// 组件数据
data() {
return {
bgIcon, // 图片资源
chart: null // ECharts 实例
}
},
// 计算属性
computed: {
// 动态 CSS 变量
cssVar() {
return {
'--size': this.size + 'px',
'--inner': Math.round(this.size * 0.7) + 'px'
}
}
},
// 生命周期钩子
mounted() {
this.init() // 初始化图表
window.addEventListener('resize', this.resize) // 监听窗口大小变化
},
// 组件销毁前清理资源
beforeDestroy() {
window.removeEventListener('resize', this.resize) // 移除事件监听
if (this.chart) {
this.chart.dispose() // 销毁 ECharts 实例
}
},
// 组件方法
methods: {
// 初始化图表
init() {
this.chart = echarts.init(this.$refs.chart)
this.chart.setOption({
color: this.legend.map(i => i.color),
series: [{
type: 'pie',
radius: ['60%', '70%'],
startAngle: 220,
endAngle: -40,
padAngle: 5,
label: { show: false },
data: this.legend.map(i => ({ name: i.name, value: 1 }))
}]
})
},
// 响应窗口大小变化
resize() {
if (this.chart) {
this.chart.resize()
}
}
}
}
</script>
<style lang="scss" scoped>
/* ---------- CSS 变量定义 ---------- */
.ratio {
--size: 250px;
--inner: 175px;
--font-xs: 12px;
--white: #fff;
--orange: #fda843;
}
/* ---------- 组件布局样式 ---------- */
.ratio {
position: relative;
width: var(--size);
height: var(--size);
margin: 0;
}
.ratio__legend {
position: absolute;
top: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
gap: 10px;
font-size: var(--font-xs);
color: var(--white);
}
.ratio__tag {
display: flex;
align-items: center;
&::before {
content: '';
width: 3px;
height: 12px;
margin-right: 4px;
background: var(--c); // 使用 CSS 变量动态设置颜色
}
}
.ratio__bg {
position: absolute;
top: 50%;
left: 50%;
width: var(--inner);
height: var(--inner);
transform: translate(-50%, -50%);
animation: rotate 3s linear infinite; // 旋转动画
}
.ratio__title {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: var(--font-xs);
color: var(--white);
b {
font-weight: normal;
}
em {
color: var(--orange);
font-style: normal;
margin-top: 2px;
}
}
.ratio__chart {
width: 100%;
height: 100%;
}
/* ---------- 旋转动画定义 ---------- */
@keyframes rotate {
to {
transform: translate(-50%, -50%) rotate(-360deg);
}
}
</style>comp-hub 组件与传统组件的区别
comp-hub 平台上的组件与传统项目中的组件有以下关键区别:
资源封装方式:
- comp-hub 组件采用自包含设计,所有依赖资源(如图像)都必须包含在组件文件夹内
- 传统项目通常将静态资源集中存放在项目级别的
assets目录
资源引用方式:
- comp-hub 组件必须使用相对路径引用所有资源
- 传统项目中常使用路径别名(如
@/assets/)简化资源引用
外部依赖处理:
- comp-hub 组件仅允许引入平台支持的第三方库(如示例中的 echarts)
- 不允许引入组件文件夹外部的自定义模块或工具函数
组件独立性:
- comp-hub 组件设计为完全独立的单元,可以在不同项目间无缝移植
- 传统项目中的组件可能依赖项目特定的全局配置、主题或工具函数
上传业务组件到平台
完成组件开发后,按照组件上传章节中的步骤将业务组件上传到 comp-hub 平台:
- 打开 comp-hub 平台并进入「上传组件」页面
- 选择您的业务组件文件夹(如本例中的
QinParamRatio) - 配置预览选项,选择
demo/index.vue作为小窗预览文件 - 填写组件描述和其他元数据
- 点击「上传」按钮完成发布
上传前预览
上传前,您可以在平台上预览组件效果,确保一切正常:

最佳实践建议
在开发和上传业务组件时,建议遵循以下最佳实践:
- 组件命名:使用有意义的组件名称,可考虑添加前缀以避免命名冲突
- 文档完善:提供详细的
README.md文件,包括组件功能、属性说明和使用示例 - 资源优化:优化组件内的图片等资源,确保组件体积合理
- 错误处理:添加适当的错误处理逻辑,提高组件的健壮性
- 版本管理:遵循语义化版本规范,清晰标记组件版本变更内容