9.9 KiB
9.9 KiB
Project Structure Skill
本 skill 定义项目的分层架构和文件组织规范,用于指导 Agent 在创建新页面、组件时遵循统一的目录结构。
核心原则
- 页面放在
pages/- 每个页面一个目录,包含index.vue - 组件放在
components/- 公共组件直接放目录下,页面专属组件按页面名分子目录 - 页面专属组件与页面同名 - 如
home页面的组件放在components/home/ - 使用 easycom 自动加载 - 无需手动 import,组件通过文件路径自动生成标签名
组件放置规则(重要)
公共组件(跨页面复用)
当用户要求创建公共组件时,直接放在 components/ 根目录下:
components/
├── backNav.vue # 通用返回导航栏
├── tabBar.vue # 通用底部栏
├── modal.vue # 通用弹窗
└── ...
标签名:<back-nav />、<tab-bar />、<modal />
页面专属组件(仅特定页面使用)
当组件只在某个页面内使用时,放在 components/{pageName}/ 子目录下:
components/
├── home/ # 首页专属组件
│ ├── status.vue
│ └── overview.vue
├── message/ # 消息页专属组件
│ └── list.vue
└── bluetooth/ # 蓝牙页专属组件
└── device.vue
标签名:<home-status />、<message-list />、<bluetooth-device />
判断依据
| 需求描述 | 放置位置 | 示例 |
|---|---|---|
| "做一个通用的返回导航" | components/backNav.vue |
<back-nav /> |
| "做一个通用的弹窗组件" | components/modal.vue |
<modal /> |
| "首页的项目列表组件" | components/home/projectList.vue |
<home-projectList /> |
| "消息页的消息列表" | components/message/list.vue |
<message-list /> |
| "蓝牙页的设备卡片" | components/bluetooth/device.vue |
<bluetooth-device /> |
目录结构
src/
├── pages/ # 页面目录
│ ├── home/ # 首页
│ │ └── index.vue
│ ├── report/ # 报告页
│ │ └── index.vue
│ ├── message/ # 消息页
│ │ └── index.vue
│ ├── bluetooth/ # 蓝牙页
│ │ └── index.vue
│ └── work/ # 工作页
│ └── index.vue
│
├── components/ # 组件目录
│ ├── backNav.vue # 公共组件:通用返回导航栏
│ │
│ ├── home/ # 首页专属组件
│ │ ├── homeNav.vue # 首页导航栏
│ │ ├── overview.vue # 今日作业概览
│ │ ├── status.vue # 实时作业状态
│ │ ├── projectList.vue # 项目列表容器
│ │ ├── list.vue # 项目列表项
│ │ ├── progress.vue # 项目作业进度
│ │ ├── construction.vue # 当前施工段
│ │ ├── warning.vue # 异常警告容器
│ │ └── warning_list.vue # 异常警告项
│ │
│ ├── message/ # 消息页专属组件
│ │ └── list.vue # 消息列表项
│ │
│ └── bluetooth/ # 蓝牙页专属组件
│ └── device.vue # 蓝牙设备卡片
│
├── composables/ # 组合式函数
├── store/ # Pinia 状态管理
├── api/ # 接口请求
├── utils/ # 工具函数
├── static/ # 静态资源
└── layouts/ # 布局组件
命名规范
文件命名
- 页面:
index.vue(固定) - 组件:
camelCase.vue(如projectList.vue) - 组合式函数:
useXxx.ts(如useCount.ts)
组件标签名(easycom 规则)
- 公共组件:
backNav.vue→<back-nav /> - 页面专属组件:
home/status.vue→<home-status /> - 嵌套组件:
home/list.vue→<home-list />
easycom 自动扫描规则
{
"easycom": {
"autoscan": true,
"custom": {
"^wd-(.*)": "@wot-ui/ui/components/wd-$1/wd-$1.vue",
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
}
}
easycom 自动生成标签名规则
| 文件路径 | 自动生成标签名 |
|---|---|
components/backNav.vue |
<back-nav /> |
components/modal.vue |
<modal /> |
components/home/status.vue |
<home-status /> |
components/message/list.vue |
<message-list /> |
components/bluetooth/device.vue |
<bluetooth-device /> |
组件拆分原则
何时拆分组件
- 模板超过 100 行 - 拆分为子组件
- 重复使用的 UI 块 - 提取为独立组件
- 逻辑独立的功能块 - 拆分便于维护
拆分模式
页面容器组件(如 projectList.vue)
└── 列表项组件(如 projectList_list.vue)
页面容器组件(如 warning.vue)
└── 列表项组件(如 warning_list.vue)
示例:项目列表
components/home/
├── projectList.vue # 容器:卡片标题 + card-body
└── projectList_list.vue # 内容:项目信息 + 参数 + 操作按钮
使用方式:
<home-projectList>
<home-projectList_list />
</home-projectList>
创建新页面步骤
-
创建页面目录
src/pages/{pageName}/index.vue -
创建页面专属组件目录(如需要)
src/components/{pageName}/ -
配置路由(如需要)
// src/pages.json { "path": "pages/{pageName}/index", "type": "page", "style": { "navigationBarTitleText": "页面标题" } } -
使用组件
页面专属组件 vs 公共组件
| 类型 | 位置 | 标签名 | 示例 |
|---|---|---|---|
| 公共组件 | components/ 根目录 |
{name} |
<back-nav /> |
| 页面专属组件 | components/{pageName}/ |
{pageName}-{name} |
<home-status /> |
页面样式规范
内容区域样式
所有使用自定义导航栏(<back-nav />)的页面,.content 容器必须使用以下样式:
.content {
padding: 16px;
padding-top: 72px;
}
padding-top: 72px为导航栏预留空间,避免内容被遮挡padding: 16px保持左右边距一致
卡片样式规范(重要)
每个组件自身就是一个卡片,页面不要用额外的 .card 容器包裹组件,否则多个组件会合并成一个卡片。
卡片间距规则:
- 卡片之间间距统一为 12px
- 页面通过
gap: 12px设置间距,组件内部不要添加 margin - 组件只负责自身样式(背景、圆角、内边距),不负责与其他组件的间距
正确做法 - 页面用 gap 设置间距:
<!-- 页面 -->
<template>
<view class="page">
<back-nav title="页面标题" />
<view class="content">
<component-a />
<component-b />
</view>
</view>
</template>
<template>
<view class="card">
<!-- 内容 -->
</view>
</template>
<!-- 组件 a.vue -->
<style scoped>
.content {
display: flex;
flex-direction: column;
gap: 12px; /* 卡片间距 */
}
</style>
<style scoped>
.card {
background: #fff;
border-radius: 12px;
padding: 16px;
/* 不要添加 margin */
}
</style>
错误做法 - 组件添加 margin 影响间距:
/* 错误:组件添加 margin */
.card {
margin-bottom: 16px; /* 不要用 margin */
}
组件卡片统一样式:
.card {
background: #fff;
border-radius: 12px;
padding: 16px;
margin-bottom: 16px;
}
例外情况 - 多个子组件需要合并展示时: 当明确要求将多个组件放在同一个卡片内时,由最外层容器组件统一设置卡片样式,子组件背景透明:
/* 容器组件 */
.container {
background: #fff;
border-radius: 12px;
padding: 16px;
}
/* 子组件 */
.child {
background: transparent;
padding: 0;
}
页面模板示例
<template>
<view class="page">
<back-nav title="页面标题" />
<view class="content">
<view class="card">
<!-- 卡片内容 -->
</view>
</view>
</view>
</template>
<style scoped>
.page {
min-height: 100vh;
background-color: #EAEFF9;
}
.content {
padding: 16px;
padding-top: 72px;
}
.card {
background: #fff;
border-radius: 12px;
padding: 16px;
}
</style>
字体规范
项目使用三级字体体系:
| 级别 | 字号 | 用途 | 示例 |
|---|---|---|---|
| 一级 | 22px | 最大标题 | 页面标题、卡片大标题 |
| 二级 | 18px | 次级正常字体 | 正文、列表项、表单标签 |
| 三级 | 14px | 最小描述字体 | 辅助说明、placeholder、元信息 |
CSS 变量:
/* 一级标题 */
--font-size-title: 22px;
/* 二级正文 */
--font-size-body: 18px;
/* 三级描述 */
--font-size-caption: 14px;
使用示例:
<template>
<view class="card">
<text class="title">
项目名称
</text>
<text class="body">
项目描述内容
</text>
<text class="caption">
辅助说明文字
</text>
</view>
</template>
<style scoped>
.title {
font-size: 22px;
font-weight: bold;
color: #333;
}
.body {
font-size: 18px;
color: #333;
}
.caption {
font-size: 14px;
color: #999;
}
</style>
注意事项
- 不要在页面中直接写大段模板 - 超过 100 行考虑拆分
- 组件样式使用 scoped - 避免样式污染
- 组件 props 要有默认值 - 提高组件易用性
- 事件命名使用 kebab-case - 如
@handle-click - 插槽优先于 props 传内容 - 灵活性更高