Components 目录
本项目组件使用 Vue 3 Composition API + <script setup> 编写,按功能模块组织。
📚 目录结构
components/
├── cards/ # 卡片组件
├── documents/ # 文档预览组件
├── examples/ # 示例组件
├── forms/ # 表单组件
├── icons/ # 图标组件
├── list/ # 列表组件
├── navigation/ # 导航组件
├── plan/ # 计划书组件
└── RichTextRenderer.vue # 富文本渲染组件
📦 组件索引
导航组件 (navigation/)
| 组件 | 功能 | Props |
|---|---|---|
NavHeader |
页面顶部导航栏 | title, showBack, preventDefaultBack |
TabBar |
底部标签导航栏 | current, tabs |
使用示例:
<template>
<NavHeader title="页面标题" />
<TabBar current="home" />
</template>
<script setup>
import NavHeader from '@/components/navigation/NavHeader.vue'
import TabBar from '@/components/navigation/TabBar.vue'
</script>
卡片组件 (cards/)
| 组件 | 功能 | Props |
|---|---|---|
MaterialCard |
资料/文档卡片 | title, icon, learners, docType, collected |
ProductCard |
产品卡片 | name, type, tags, collected |
使用示例:
<template>
<MaterialCard
:title="item.title"
:icon="item.icon"
:learners="item.learners"
:doc-type="item.docType"
:collected="item.collected"
@view="handleView"
/>
</template>
<script setup>
import MaterialCard from '@/components/cards/MaterialCard.vue'
</script>
表单组件 (forms/)
| 组件 | 功能 | Props |
|---|---|---|
SearchBar |
搜索栏 | modelValue, placeholder, disabled |
FilterTabs |
筛选标签 | options, modelValue |
使用示例:
<template>
<SearchBar v-model="searchText" placeholder="搜索资料" />
<FilterTabs v-model="activeTab" :options="tabs" />
</template>
<script setup>
import SearchBar from '@/components/forms/SearchBar.vue'
import FilterTabs from '@/components/forms/FilterTabs.vue'
</script>
列表组件 (list/)
| 组件 | 功能 | Props |
|---|---|---|
SectionCard |
分组卡片容器 | title |
SectionItem |
分组列表项 | title, subtitle, icon |
LoadMoreList |
加载更多列表 | items, hasMore, loading |
ListItemActions |
列表项操作按钮 | viewable, collectable, deletable |
使用示例:
<template>
<SectionCard title="常用功能">
<SectionItem
v-for="item in items"
:key="item.id"
:title="item.title"
:subtitle="item.subtitle"
:icon="item.icon"
@click="handleClick"
/>
</SectionCard>
<LoadMoreList
:items="list"
:hasMore="hasMore"
:loading="loading"
@load-more="loadMore"
/>
</template>
<script setup>
import SectionCard from '@/components/list/SectionCard.vue'
import SectionItem from '@/components/list/SectionItem.vue'
import LoadMoreList from '@/components/list/LoadMoreList/index.vue'
</script>
文档组件 (documents/)
| 组件 | 功能 | Props |
|---|---|---|
PdfPreview |
PDF 预览 | url |
OfficeViewer |
Office 文档查看器 | url |
DocumentPreview |
通用文档预览 | file |
富文本组件
| 组件 | 功能 | Props |
|---|---|---|
RichTextRenderer |
富文本渲染 | content, enableTransform |
使用示例:
<template>
<RichTextRenderer
:content="htmlContent"
:enable-transform="true"
@image-preview="handlePreview"
@file-click="handleFileClick"
/>
</template>
<script setup>
import RichTextRenderer from '@/components/RichTextRenderer.vue'
const htmlContent = '<p>HTML 内容</p>'
</script>
计划书组件 (plan/)
弹窗容器
| 组件 | 功能 |
|---|---|
PlanPopupNew |
计划书弹窗容器 |
PlanFormContainer |
计划书表单容器 |
表单字段 (PlanFields/)
| 组件 | 功能 |
|---|---|
NameInput |
姓名输入 |
AgePickerGlobal |
年龄选择器 |
DatePickerGlobal |
日期选择器 |
SelectPickerGlobal |
选项选择器 |
AmountKeyboard |
金额键盘 |
PaymentPeriodRadio |
缴费年期单选 |
RadioGroup |
单选分组 |
模板 (PlanTemplates/)
| 组件 | 功能 |
|---|---|
SavingsTemplate |
储蓄险模板 |
LifeInsuranceTemplate |
寿险模板 |
CriticalIllnessTemplate |
重疾险模板 |
图标组件 (icons/)
| 组件 | 功能 | Props |
|---|---|---|
IconFont |
IconFont 图标 | name, size, color |
使用示例:
<template>
<IconFont name="home" :size="28" color="#3B82F6" />
<IconFont name="search" />
</template>
<script setup>
import IconFont from '@/components/icons/IconFont.vue'
</script>
🎯 组件使用规范
Props 定义
<script setup>
// ✅ GOOD - 有类型和默认值
const props = defineProps({
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
})
// ❌ BAD - 缺少类型
const props = defineProps(['title', 'count'])
</script>
Emits 定义
<script setup>
// ✅ GOOD - 明确定义事件
const emit = defineEmits(['update:modelValue', 'change', 'submit'])
// 使用
emit('update:modelValue', newValue)
emit('change', newValue)
</script>
样式规范
<style scoped>
/* ✅ 使用 TailwindCSS(80%) */
.container {
@apply flex items-center justify-center p-4 bg-white rounded-lg;
}
/* ✅ 使用 Less(20%)- 深度选择器、特定样式 */
:deep(.nut-input) {
border-radius: 12rpx !important;
}
</style>
🔧 核心组件详解
NavHeader.vue
页面顶部导航栏,支持返回按钮。
Props: | Prop | 类型 | 默认值 | 说明 | |------|------|--------|------| | title | String | - | 页面标题 | | showBack | Boolean | true | 是否显示返回按钮 | | preventDefaultBack | Boolean | false | 阻止默认返回行为 |
Events: | Event | 说明 | |-------|------| | back | 点击返回按钮时触发 |
使用示例:
<NavHeader
title="资料详情"
:show-back="true"
:prevent-default-back="true"
@back="handleCustomBack"
/>
TabBar.vue
底部标签导航栏,支持红点提醒。
Props: | Prop | 类型 | 默认值 | 说明 | |------|------|--------|------| | current | String | 'home' | 当前激活的标签 |
红点自动同步:
- 组件自动从
userStore.tabBarBadges读取红点状态 - 无需手动传入 badges prop
使用示例:
<TabBar current="home" />
MaterialCard.vue
资料/文档卡片,展示资料信息和操作按钮。
Props: | Prop | 类型 | 说明 | |------|------|------| | title | String | 资料标题 | | icon | String | 图标名称 | | learners | String | 学习人数 | | docType | String | 文档类型 | | fileSize | String | 文件大小 | | collected | Boolean | 是否已收藏 | | id | Number/String | 资料 ID |
Events: | Event | 说明 | |-------|------| | view | 查看资料 | | collect | 收藏/取消收藏 |
SearchBar.vue
搜索栏组件,支持清除和搜索。
Props: | Prop | 类型 | 默认值 | 说明 | |------|------|--------|------| | modelValue | String | '' | 绑定值(v-model) | | placeholder | String | '搜索' | 占位文本 | | disabled | Boolean | false | 是否禁用 | | showClear | Boolean | true | 是否显示清除按钮 |
Events: | Event | 说明 | |-------|------| | update:modelValue | 输入变化 | | search | 点击搜索或回车 |
使用示例:
<SearchBar
v-model="searchText"
placeholder="搜索资料"
@search="handleSearch"
/>
IconFont.vue
IconFont 图标组件。
Props: | Prop | 类型 | 默认值 | 说明 | |------|------|--------|------| | name | String | - | 图标名称 | | size | Number/String | 20 | 图标大小 | | color | String | '#333' | 图标颜色 |
使用示例:
<IconFont name="home" :size="28" color="#3B82F6" />
RichTextRenderer.vue
富文本渲染组件,基于 Taro v-html 实现。
Props: | Prop | 类型 | 默认值 | 说明 | |------|------|--------|------| | content | String | '' | HTML 内容字符串 | | enableTransform | Boolean | true | 是否启用图片自动处理 |
Events: | Event | 说明 | 参数 | |-------|------|------| | image-preview | 图片预览时触发 | { src } | | file-click | 文件链接点击时触发 | { url, fileName } |
功能特性:
- HTML 实体自动解码
-
<a>标签自动替换为<div data-href=""> - 图片长按预览
- 文件链接点击处理
- 自动处理图片样式(widthFix, max-width: 100%)
使用示例:
<template>
<RichTextRenderer
:content="article.content"
:enable-transform="true"
@image-preview="handlePreview"
@file-click="handleFileClick"
/>
</template>
<script setup>
import RichTextRenderer from '@/components/RichTextRenderer.vue'
const handlePreview = ({ src }) => {
console.log('预览图片:', src)
}
const handleFileClick = ({ url, fileName }) => {
console.log('打开文件:', fileName, url)
}
</script>
📖 最佳实践
组件抽取原则
必须抽取为组件:
- ✅ UI 在 3 个及以上页面重复
- ✅ 复杂的业务逻辑需要封装
- ✅ 可复用的表单控件
组件命名规范
// ✅ GOOD - 多词组合,PascalCase
MaterialCard.vue
SearchBar.vue
AgePickerGlobal.vue
// ❌ BAD - 单词,不清晰
Card.vue
Input.vue
Picker.vue
Props vs Emits
<script setup>
// ✅ GOOD - 数据向下传递
const props = defineProps({
modelValue: String
})
// ✅ GOOD - 事件向上传递
const emit = defineEmits(['update:modelValue', 'change'])
// 使用
emit('update:modelValue', newValue)
</script>