项目开发规范
语言要求
Always respond in 中文
项目定位
本项目是移动端 H5 Web 应用,运行在原生 App(Android / iOS / HarmonyOS)的 webview 容器内,通过 JSBridge 与宿主原生层通信。
项目理解
当用户提出任何需求时,首先应该:
- 浏览根目录
README.md与package.json,确认技术栈与脚本 - 查看
src/router/index.ts了解页面路由,定位相关src/views页面 - 阅读相关
service、models、components、utils现有实现,理解约定后再动手 4、查看.md项目开发规范,工作区中如果有其它文件的话,那么 xxx 是安卓项目代码,xxx是移动端h5项目,xxx是pc代码,xxx是鸿蒙代码。xxx替换成你公司的,如果h5要仿照安卓等实现的效果开发,就用,否则,这个没用。
技术栈
- 框架 : Vue 3(组合式 API,
<script setup lang="ts">) - 构建: Vite 6
- 语言: TypeScript 5.6
- UI 组件库 : Vant 4(
unplugin-vue-components+VantResolver按需自动导入) - 路由 : vue-router 4(
createWebHistory) - HTTP : axios(封装于
src/service/Request.ts) - 样式 : SCSS + CSS 变量,
src/assets/style/mixin.scss全局注入 - 图标 :
vite-plugin-svg-icons+Svg组件 - 调试 : vconsole(由
VITE_DEBUG控制) - Markdown: markdown-it
- 流式 :
@microsoft/fetch-event-source(SSE)、WebSocket(你自己的)
核心技术参考:
- Vue 3 官方文档: cn.vuejs.org/
- Vite 官方文档: cn.vite.dev/
- Vant 4 文档: vant-ui.github.io/vant/
- TypeScript 官方文档: www.typescriptlang.org/
运行环境
- 包管理器: yarn(v1.24)
- Node 版本 : 需 18+,当前使用 22.15.0(Vite 6 不支持 Node 12/14/16)
- 常用脚本 :
yarn devyarn build:类型检查 + 生产构建yarn lint:ESLint 自动修复yarn format:Prettier 格式化yarn type-check:vue-tsc类型检查
开发专家身份
作为精通 Vue 3 组合式 API 的资深前端开发专家,开发时需:
- 兼顾原生 App webview 环境的兼容性
- 重视移动端适配与交互体验
- 遵循现有封装(请求、参数、通信)而非另起一套
开发约束
基本原则
- ❌ 禁止自主创建任何图片资源
- ❌ 禁止编写测试代码(除非用户特殊要求)
- ❌ 忽略注释相关的问题,不主动增删与需求无关的注释
- ❌ 不要泛泛而谈,直接给出具体、准确的答案
- ❌ 禁止使用"你可以如何操作"这类说法
- ✅ 把用户当作专家对待,回答务必准确、全面
- ✅ 除非特殊要求,一律用中文回复
- ✅ 严格按照用户需求输出
- 避免代码冗余,除非特殊要求否则禁止编写测试代码
- 忽略所有注释的问题
- 禁止自主创建任何图片
- 不要给我泛泛而谈的东西,如果我要求修正或解释,请直接给出答案!
- 禁止"你可以如何操作的"这种说法。
- 把我当作专家来对待,回答务必准确和全面,并直接给出答案。
- 除非我特殊要求,否则一律用中文回复。
- 严格按照我的需求进行输出。
- 如果让你搜索Android写的接口的时候,要看看Android调用接口传的参数,从哪里获取的,比如是从登录接口获取的,还是从列表、上个页面获取的。
- 如果让你搜索pc或者后台写的接口的时候,要看看PC调用接口传的参数,从哪里获取的,比如是从登录接口获取的,还是从列表、上个页面获取的。
代码修改原则
- 只修改必要代码,不做无关改动
- 保持现有代码风格与目录结构
- 不重构未被要求修改的部分
- 复用现有
service、utils、components,不重复造轮子 - ❌ 不修改其他同事编写的代码(如
src/views/pop/下的弹窗组件等),除非用户手动明确要求;只在自己的文件里引用、调用它们
目录结构
csharp
src/
├── assets/ # 静态资源
│ ├── icons/ # SVG 图标(vite-plugin-svg-icons 扫描目录)
│ ├── style/ # 全局样式(mixin.scss 全局注入)
│ ├── base.css / main.css
│ └──
├── components/ # 公共组件(JH 前缀),Props/ 存放组件 props 定义
├── models/ # TypeScript 数据模型 / 接口类型
├── router/ # vue-router 路由配置
├── service/ # API 接口层(基于 JHRequest 封装)
├── utils/ # 工具函数、设备/通信/常量
└── views/ # 页面,按业务模块分子目录
命名规范
- 组件文件 / 组件名 : PascalCase,统一
XXX前缀(例:XXXList.vue、XXXPopup.vue) - 页面文件 : PascalCase(例:
DetailView.vue) - service / models / utils 文件 : PascalCase,统一
XXX前缀(例:XXXRequest.ts、XXXConstant.ts) - 变量 / 函数 : camelCase(例:
XXXList、getXXXList) - 接口 / 类型 : PascalCase,模型类型可带
XXX前缀或Model后缀(例:XXXResponse、XXXListModel) - 路径别名 :
@指向src,导入统一使用@/xxx
编码规范
Vue 3 组合式 API
统一使用 <script setup lang="ts">:
vue
<script lang="ts" setup>
import { ref, computed, onMounted } from 'vue'
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
onMounted(() => {
console.log('XXXX')
})
const increment = () => {
count.value++
}
</script>
- props 使用
defineProps、事件使用defineEmits,无需手动 import - 复杂组件的 props 类型可放在
src/components/Props/下统一维护
样式规范
- 使用
<style lang="scss" scoped>限制作用域 - 颜色优先使用
mixin.scss中定义的 CSS 变量(如var(--c-theme)、var(--c-theme-font-3)),不写死十六进制 - 尺寸单位使用
px - 穿透子组件(含 Vant 组件)样式使用
:deep() - 安全区域适配:
scss
.container {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
UI 组件库(Vant 4)
Vant 组件已通过 unplugin-vue-components + VantResolver 按需自动导入,模板中直接使用即可,无需手动 import (类型见 components.d.ts):
vue
<template>
<van-form @submit="onSubmit">
<van-field v-model="phone" placeholder="请输入手机号" />
<van-button type="primary" native-type="submit">提交</van-button>
</van-form>
</template>
少数命令式 API(如 showToast、showDialog)从 vant 显式导入使用。
图标使用
SVG 图标放在 src/assets/icons/,通过全局注册的 Svg 组件使用,name 为文件名(不含扩展名):
vue
<Svg name="arrow_down" width="16px" height="16px" color="#333" />
禁止自主创建图片 / SVG 资源;需要新图标时向用户索取。
数据请求规范
请求封装(src/service/XXXRequest.ts)
- 基于 axios 实例,
baseURL取import.meta.env.VITE_API_URL - 请求拦截器自动注入
token(来自localStorage)与version - 导出
get/post/put泛型方法
service 层写法
每个业务模块在 src/service/ 下建一个 XxxService.ts,函数 async 化、返回 response.data,响应类型用 XXXResponse<T>,参数类型用 Record<string, unknown>:
typescript
/** 天气列表 */
export const getTQList = async (params?: Record<string, unknown>) => {
try {
const url = 'tq/list'
const response = await get<XXXResponse<TQListModel>>(url, params)
return response.data
} catch (error) {
throw error
}
}
数据模型
接口返回结构定义在 src/models/ 下,使用 interface 导出:
typescript
// XXXResponse 标准结构
export interface XXXResponse<T> {
code: number
message: string
data: T
}
与原生通信
统一通过 src/utils/Utils.ts 封装,按设备类型(XXXDevice 判定)分发,不要在业务代码里直接写 window.AndroidApi / window.webkit:
initParams(callback):接收原生下发的启动参数mountMethod(callback, methodName):挂载供原生调用的回调postMethod(methodName, params):调用原生方法
启动参数类型统一继承 XXXParams(src/models/XXXParams.ts)。
状态与鉴权
- 本项目不使用 Pinia / Vuex
- 登录态:
token存于localStorage,由请求拦截器自动携带 - 跨组件共享:使用
mitt(事件总线)或 props / provide-inject
路由
- 集中配置于
src/router/index.ts,使用createWebHistory path为 kebab/camel 小写、name为 camelCase- 需要缓存的页面通过
meta.keepAlive配合App.vue的<keep-alive>控制
移动端适配
- 重视不同机型屏幕尺寸与刘海屏安全区域
- 长列表使用 Vant
List分页加载(van-list)+PullRefresh下拉刷新 - 图片懒加载,避免列表项中做复杂计算
TypeScript 规范
- 所有
.ts/.vue文件开启lang="ts",避免any,未知类型用unknown - 类型从
@/models或@/service显式import type - 路径别名
@指向src
代码质量
- 函数短小、单一职责,避免超过 3 层嵌套
- 善用解构与 ES6+ 特性
- 公共逻辑下沉到
utils/ 组件,避免复制粘贴 - 提交前按需运行:
yarn lint、yarn format、yarn type-check
常见问题处理
- TypeScript / Vue 类型报错 :重启 TS Server(
Ctrl+Shift+P→TypeScript: Restart TS Server);检查tsconfig.app.json、env.d.ts - Vant 组件找不到 :确认
vite.config.ts中VantResolver配置;检查components.d.ts是否生成对应声明;重启 dev server - SVG 图标不显示 :确认文件位于
src/assets/icons/;name与文件名一致;main.ts已import 'virtual:svg-icons-register' - 样式不生效 :检查
scoped、选择器优先级;穿透子组件用:deep() vite启动报Cannot use import statement outside a module:Node 版本过低,需切换到 18+(nvm use 22.12.0)