跳转至

前端开发规范 (Frontend Development)

定位:Vue 3 + TypeScript 企业级前端开发标准,确保类型安全、可维护性。


技术选型

层级 技术栈 版本要求 选型理由
构建工具 Vite ≥ 5.0 热更新秒级体验,比 Webpack 快
框架 Vue 3 ≥ 3.3 Composition API、Vapor Mode 前景好
类型系统 TypeScript ≥ 5.0 必须开启 strict 模式
状态管理 Pinia ≥ 2.0 体积仅 1.5KB,TS 支持好
路由 Vue Router ≥ 4.0 类型安全的路由配置
UI 框架 (后端) Element Plus ≥ 2.0 企业级组件库,完善生态
UI 框架 (前端) Vant 4 ≥ 4.0 轻量移动端组件库,针对 H5 端优化
样式框架 (前端) UnoCSS ≥ 0.60 原子化 CSS,按需生成,极致性能
动画库 GSAP ≥ 3.0 高性能 JS 动画,时间线控制,ScrollTrigger 等插件
3D 渲染 Three.js ≥ 0.160 WebGL 3D 图形库,场景/相机/材质/光照完备体系
包管理 pnpm ≥ 8.0 磁盘空间高效、依赖管理严格

⚠️ 注意:Vuex 5 开发基本停滞,新项目不推荐使用


项目结构

src/
├── api/                  # API 接口层
│   ├── modules/          # 按业务模块拆分
│   │   ├── user.ts
│   │   └── order.ts
│   └── index.ts
├── components/           # 全局通用组件
│   ├── base/             # 基础组件 (BaseInput, BaseTable)
│   └── business/         # 业务通用组件
├── composables/          # 组合式函数(带响应式逻辑)
│   ├── useAuth.ts
│   └── useRequest.ts
├── utils/                # 纯工具函数(无响应式)
├── stores/               # Pinia 状态管理
│   ├── modules/
│   └── index.ts
├── types/                # 全局类型定义
│   ├── api.d.ts
│   └── global.d.ts
├── views/                # 页面组件(按业务模块拆分)
├── router/               # 路由配置
└── env.d.ts              # .vue 文件类型声明

关键原则

目录 职责
composables/ 响应式逻辑(如 useAuthuseRequest
utils/ 纯函数(如 formatDatedebounce
types/ 全局类型,组件内部类型可写在组件文件内

命名规范

类型 规范 示例
组合式函数 use + 功能名 useAuthuseRequest
Store 功能名 + Store useUserStore
组件 多词命名 (PascalCase) UserProfileOrderList
路由模块 功能域命名 userRoutes
文件名 kebab-case user-profile.vue

TypeScript 规范

tsconfig.json 关键配置

{
  "compilerOptions": {
    "strict": true,
    "moduleResolution": "bundler",
    "paths": { "@/*": ["./src/*"] }
  }
}

Props 类型定义

interface Props {
  title: string
  count?: number
  items: string[]
}

// 带默认值
const props = withDefaults(defineProps<Props>(), {
  count: 0,
  items: () => []
})

Emits 类型定义(Vue 3.3+)

const emit = defineEmits<{
  update: [value: string]
  delete: [id: number]
}>()

.vue 文件类型声明

// src/env.d.ts
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

状态管理(Pinia)

推荐写法:Composition API 风格

export const useUserStore = defineStore('user', () => {
  // state
  const token = ref<string>('')
  const userInfo = ref<UserInfo | null>(null)

  // getters
  const isLoggedIn = computed(() => !!token.value)

  // actions(直接修改 state,无需 mutations)
  const setToken = (newToken: string) => {
    token.value = newToken
  }

  return { token, userInfo, isLoggedIn, setToken }
})

使用注意事项

// ❌ 错误:解构后失去响应式
const { userName, isLoggedIn } = userStore

// ✅ 正确:使用 storeToRefs 解构响应式属性
const { userName, isLoggedIn } = storeToRefs(userStore)

// ✅ actions 可以直接解构(普通函数)
const { logout, fetchUserInfo } = userStore

路由配置

类型安全的 meta 定义

declare module 'vue-router' {
  interface RouteMeta {
    title?: string
    requiresAuth?: boolean
    roles?: string[]
  }
}

权限守卫

export function setupAuthGuard(router: Router) {
  router.beforeEach((to, from, next) => {
    const userStore = useUserStore()

    if (!to.meta.requiresAuth) return next()
    if (!userStore.isLoggedIn) {
      return next({ path: '/login', query: { redirect: to.fullPath } })
    }
    next()
  })
}

UI 框架规范

框架选择指南

场景 推荐框架 说明
后端管理系统 Element Plus 表单、表格、弹窗等企业级组件
前台用户界面 UnoCSS 灵活定制、原子化样式
H5 移动端 Vant 4 轻量移动端组件库,针对 H5 端优化
混合项目 按需组合 按端类型选择(PC 端 Element Plus / H5 端 Vant 4)

Element Plus(后端 UI)

适用于:后台管理系统、数据看板、表单密集型页面

按需引入

// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default {
  plugins: [
    AutoImport({ resolvers: [ElementPlusResolver()] }),
    Components({ resolvers: [ElementPlusResolver()] })
  ]
}

布局规范

规则 说明
全屏容器 width: 100%, min-height: 100vh, margin: 0
盒模型 全局启用 box-sizing: border-box
滚动策略 严禁表格内固定高度滚动,使用原生页面级滚动
栅格系统 必须使用 el-row / el-col (:span="24")

表格规范

<!-- 必须开启 stripe 属性 -->
<el-table :data="tableData" stripe>
  <el-table-column prop="name" label="名称" />
</el-table>

Vant 4(H5 前端 UI)

适用于:移动端 H5 页面、微信内嵌页、移动端表单/列表/轻交互

安装配置

pnpm add vant
// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { VantResolver } from 'unplugin-vue-components/resolvers'

export default {
  plugins: [
    AutoImport({ resolvers: [VantResolver()] }),
    Components({ resolvers: [VantResolver()] })
  ]
}

核心组件

<template>
  <!-- 导航栏 -->
  <van-nav-bar title="标题" left-text="返回" right-text="按钮" />

  <!-- 表单 -->
  <van-form @submit="onSubmit">
    <van-field v-model="username" name="用户名" label="用户名" placeholder="请输入用户名" />
    <van-field v-model="password" type="password" name="密码" label="密码" placeholder="请输入密码" />
    <div style="margin: 16px;">
      <van-button round block type="primary" native-type="submit">提交</van-button>
    </div>
  </van-form>

  <!-- 单元格列表 -->
  <van-cell-group>
    <van-cell title="设置" is-link />
    <van-cell title="关于" is-link />
  </van-cell-group>

  <!-- 弹出层 -->
  <van-popup v-model:show="showPopup" position="bottom" round>
    <div class="p-4">底部弹出内容</div>
  </van-popup>
</template>

H5 适配(Viewport + rem/px)

// 方案一:postcss-pxtorem(推荐)
pnpm add -D postcss-pxtorem

// postcss.config.js
export default {
  plugins: {
    'postcss-pxtorem': {
      rootValue: 37.5, // Vant 设计稿 375
      propList: ['*'],
      selectorBlackList: ['.norem']
    }
  }
}

使用规范

规则 说明
按需引入 使用 unplugin-vue-components 自动按需加载,禁止全局引入
主题定制 通过 CSS 变量覆盖 --van-primary-color
设计稿 Vant 基于 375px 设计稿,使用 postcss-pxtorem 适配
与 Element Plus 共存 同一项目按端分离,H5 路由页面仅用 Vant,PC 路由页面仅用 Element Plus

UnoCSS(前端 UI)

适用于:用户前台、营销页面、高度定制化界面

UnoCSS 是原子化 CSS 引擎,相比 Tailwind CSS 无需解析、按需生成、无核心工具集,构建性能更高。

安装配置

pnpm add unocss
// vite.config.ts
import UnoCSS from 'unocss/vite'

export default {
  plugins: [UnoCSS()]
}
// uno.config.ts
import { defineConfig, presetUno, presetAttributify } from 'unocss'

export default defineConfig({
  presets: [
    presetUno(),
    presetAttributify() // 支持属性模式:<button uno-text="red">
  ],
  shortcuts: [
    ['btn', 'px-4 py-2 rounded-lg font-medium transition-colors'],
    ['btn-primary', 'btn bg-blue-500 text-white hover:bg-blue-600'],
  ],
  theme: {
    colors: {
      primary: '#3b82f6',
      secondary: '#64748b',
    }
  }
})
// main.ts
import 'virtual:uno.css'

核心用法

<template>
  <!-- 布局 -->
  <div class="flex items-center justify-between p-4 bg-white rounded-lg shadow">
    <h1 class="text-2xl font-bold text-gray-900">标题</h1>
    <button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
      按钮
    </button>
  </div>

  <!-- 响应式 -->
  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
    <div class="p-4 bg-gray-100">卡片</div>
  </div>

  <!-- 使用 shortcuts -->
  <button class="btn-primary">提交</button>
</template>

常用工具类(与 Tailwind CSS 兼容)

类别 示例
布局 flex, grid, items-center, justify-between
间距 p-4, m-2, gap-4, space-x-2
尺寸 w-full, h-screen, max-w-xl
文字 text-lg, font-bold, text-gray-500
背景 bg-white, bg-blue-500, bg-opacity-50
边框 border, rounded-lg, shadow-md
响应式 md:flex, lg:grid-cols-3

自定义快捷方式

// uno.config.ts
export default defineConfig({
  shortcuts: [
    // 静态快捷方式
    ['btn-primary', 'px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600'],
    // 动态快捷方式
    [/^btn-(.*)$/, ([, c]) => `bg-${c}-500 text-white px-4 py-2 rounded hover:bg-${c}-600`],
  ]
})

与 Vue 组件结合

<script setup lang="ts">
const props = withDefaults(defineProps<{
  variant?: 'primary' | 'secondary'
}>(), {
  variant: 'primary'
})
</script>

<template>
  <button
    class="px-4 py-2 rounded-lg text-white transition-colors"
    :class="{
      'bg-blue-500 hover:bg-blue-600': variant === 'primary',
      'bg-gray-500 hover:bg-gray-600': variant === 'secondary'
    }"
  >
    <slot />
  </button>
</template>

GSAP(动画库)

适用于:页面滚动动画、元素进入/离开过渡、复杂时间线动画、SVG 动画

安装配置

pnpm add gsap

基础用法

import gsap from 'gsap'

// 带动画的 ref
const boxRef = ref<HTMLElement>()

onMounted(() => {
  gsap.from(boxRef.value, {
    duration: 1,
    x: -100,
    opacity: 0,
    ease: 'power2.out'
  })
})

ScrollTrigger 滚动触发

pnpm add gsap @gsap/scrolltrigger
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'

gsap.registerPlugin(ScrollTrigger)

onMounted(() => {
  gsap.from('.card', {
    scrollTrigger: '.card',
    y: 50,
    opacity: 0,
    duration: 0.8,
    stagger: 0.2
  })
})

使用规范

规则 说明
清理 onUnmounted 中使用 gsap.killTweensOf(ref) 清理动画
响应式 动画参数使用 ref 绑定,避免硬编码数值
性能 尽量使用 transformopacity,避免触发重排的属性

Three.js(3D 渲染)

适用于:3D 产品展示、数据可视化、交互式场景、品牌动效

安装配置

pnpm add three
pnpm add -D @types/three

基础场景

import * as THREE from 'three'

const containerRef = ref<HTMLElement>()

onMounted(() => {
  // 场景 / 相机 / 渲染器
  const scene = new THREE.Scene()
  const camera = new THREE.PerspectiveCamera(75, containerRef.value!.clientWidth / containerRef.value!.clientHeight, 0.1, 1000)
  const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
  renderer.setSize(containerRef.value!.clientWidth, containerRef.value!.clientHeight)
  containerRef.value!.appendChild(renderer.domElement)

  // 添加几何体
  const geometry = new THREE.BoxGeometry()
  const material = new THREE.MeshStandardMaterial({ color: 0x3b82f6 })
  const cube = new THREE.Mesh(geometry, material)
  scene.add(cube)

  // 光照
  const light = new THREE.DirectionalLight(0xffffff, 1)
  light.position.set(5, 5, 5)
  scene.add(light)

  camera.position.z = 5

  // 渲染循环
  const animate = () => {
    requestAnimationFrame(animate)
    cube.rotation.x += 0.01
    cube.rotation.y += 0.01
    renderer.render(scene, camera)
  }
  animate()

  // 响应式
  window.addEventListener('resize', () => {
    camera.aspect = containerRef.value!.clientWidth / containerRef.value!.clientHeight
    camera.updateProjectionMatrix()
    renderer.setSize(containerRef.value!.clientWidth, containerRef.value!.clientHeight)
  })
})
<template>
  <div ref="containerRef" class="w-full h-96" />
</template>

使用规范

规则 说明
清理 onUnmounted 中调用 renderer.dispose() 释放 GPU 资源
按需加载 Three.js 体积大,使用动态 import() 按路由懒加载
性能 控制几何体面数,使用 requestAnimationFrame 而非 setInterval

常见陷阱

文件上传重置

handleFileChange(e: Event) {
  // 处理逻辑...
  e.target.value = ''  // 必须重置,否则重复选择同一文件不触发
}

Markdown 渲染

const renderMarkdown = (text: string): string => {
  if (!text) return ''
  let html = text.replace(/\n/g, '<br>')
  html = html.replace(/<br>- /g, '<br><span class="md-list-item">• </span>')
  html = html.replace(/`([^`]+)`/g, '<code class="md-code">$1</code>')
  return html
}

工程化配置

ESLint 9(Flat Config)

// eslint.config.js
export default [
  js.configs.recommended,
  ...vue.configs['flat/recommended'],
  {
    files: ['**/*.{ts,tsx,vue}'],
    languageOptions: {
      parser: vueParser,
      parserOptions: { parser: tsParser }
    }
  }
]

自动导入

// vite.config.ts
AutoImport({
  imports: ['vue', 'vue-router', 'pinia'],
  dts: 'src/auto-imports.d.ts'
})

配置后可直接使用 ref()computed() 无需手动 import。


沉淀协议

场景 行动
新组件模式重复 ≥ 3 次 提取到 components/base/
API 调用模式重复 ≥ 3 次 封装到 composables/useRequest.ts
样式规范固化 更新本文档

多项目共用依赖 (Monorepo 模式)

适用场景:web/ 目录下多个 Vue 3 项目共用一套依赖,避免重复安装。

目录结构

web/
├── node_modules/           # 共用依赖 (Vue 3, Pinia, Vue Router 等)
├── package.json            # 共用依赖声明
├── pnpm-workspace.yaml     # pnpm 工作区配置
├── .vue-global/            # (可选) 全局类型声明、共享组件
│   └── types/
│       └── global.d.ts
├── project-a/              # 独立项目 A
│   ├── package.json        # 项目特有依赖
│   ├── vite.config.ts
│   └── src/
└── project-b/              # 独立项目 B
    ├── package.json
    ├── vite.config.ts
    └── src/

pnpm 工作区配置

# web/pnpm-workspace.yaml
packages:
  - 'project-a'
  - 'project-b'

共用依赖 package.json

{
  "name": "aiasme-web-workspace",
  "private": true,
  "dependencies": {
    "vue": "^3.4.0",
    "vue-router": "^4.3.0",
    "pinia": "^2.1.0",
    "element-plus": "^2.6.0"
  },
  "devDependencies": {
    "vite": "^5.4.0",
    "typescript": "^5.4.0",
    "@vitejs/plugin-vue": "^5.0.0"
  }
}

子项目 package.json

{
  "name": "project-a",
  "version": "1.0.0",
  "dependencies": {
    "vue": "workspace:*"
  },
  "devDependencies": {
    "vite": "workspace:*",
    "typescript": "workspace:*"
  }
}

使用规范

规则 说明
共用依赖位置 web/package.json 声明 Vue 3 核心生态库
项目特有依赖 子项目 package.json 仅声明业务特有依赖
版本锁定 使用 workspace:* 引用工作区版本,确保一致
安装命令 web/ 目录执行 pnpm install
独立运行 子项目可独立 pnpm dev,自动使用共享依赖

vite.config.ts 配置

// web/project-a/vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  // 确保解析到工作区根目录的 node_modules
  resolve: {
    dedupe: ['vue', 'vue-router', 'pinia']
  }
})

新建 Web 项目流程

  1. web/ 下创建项目目录
  2. 创建 package.json,使用 workspace:* 引用共享依赖
  3. 配置 vite.config.ts,添加 dedupe 防止重复打包
  4. web/ 根目录执行 pnpm install

禁止事项

禁止 原因
子项目独立安装 Vue 3 导致版本冲突、包体积膨胀
省略 dedupe 配置 Vite 可能重复打包 Vue
不同项目使用不同 Vue 版本 破坏共享依赖一致性