Skip to content

编码规范

命名

方法

类型规范示例
事件处理handle + 动词 + 名词handleLoginClickhandleFormSubmit
数据加载load/fetch + 名词loadUserInfofetchOrderList
布尔判断is/has/should + 形容词/名词isLoadinghasPermission
状态切换toggle + 名词toggleThemetoggleMenu
数据验证validate + 名词validateFormvalidatePhone
数据格式化format + 名词formatDateformatBytes
typescript
// ✅
const handleLoginClick = () => { /* ... */ }
const loadUserInfo = async () => { /* ... */ }
const isLoading = ref(false)

// ❌
const click = () => { /* ... */ }
const getUserInfo = async () => { /* ... */ }  // 应该用 load/fetch
const loading = ref(false)  // 应该用 isLoading

变量

typescript
// 布尔值:is/has/should 前缀
const isLoading = ref(false)
const hasPermission = computed(() => !!getAccessToken())

// 数组:复数形式
const userList = ref([])
const menuItems = ref([])

// 对象:单数形式
const userInfo = ref({})
const formData = ref({})

文件

类型规范示例
页面kebab-caseuser-profile.vue
组件PascalCaseUserCard.vue
ComposablescamelCase + use 前缀useCountdown.ts
工具函数camelCasepermission.ts
类型定义PascalCaseUser.ts

Composables

满足任一条件时提取:

  1. 逻辑复用 — 多个组件使用相同逻辑
  2. 状态管理 — 复杂的响应式状态
  3. 副作用封装 — 定时器、事件监听等
typescript
// composables/useCountdown.ts
export function useCountdown(duration = 60) {
  const countdown = ref(0)
  const isRunning = ref(false)
  let timer: ReturnType<typeof setInterval> | null = null

  const start = () => {
    if (isRunning.value) return
    countdown.value = duration
    isRunning.value = true
    timer = setInterval(() => {
      countdown.value--
      if (countdown.value <= 0) stop()
    }, 1000)
  }

  const stop = () => {
    if (timer) { clearInterval(timer); timer = null }
    countdown.value = 0
    isRunning.value = false
  }

  onUnmounted(() => stop())

  return { countdown, isRunning, start, stop }
}

工具函数

utils/
├── format.ts       # 格式化(日期、金额、文件大小)
├── permission.ts   # 权限判断
├── auth.ts         # 认证相关
├── request.ts      # 网络请求
└── storage.ts      # 本地存储

原则:纯函数优先、避免依赖 Vue 实例、单一职责。

错误处理

typescript
// 统一在 request.ts 处理,业务层只需 try/catch 特殊场景
async function loadUserData() {
  try {
    userData.value = await UserAPI.getUserInfo()
  } catch {
    // 特殊业务处理(如提示用户重试)
  }
}

// ❌ 不要到处写网络重试逻辑
const loadData = async (retryCount = 3) => { ... }

跨平台兼容

typescript
// 条件编译
// #ifdef MP-WEIXIN
uni.setStorageSync(key, value)
// #endif

// #ifdef H5
window.localStorage.setItem(key, value)
// #endif

安全区域

scss
.tabbar {
  padding-bottom: constant(safe-area-inset-bottom); /* iOS < 11.2 */
  padding-bottom: env(safe-area-inset-bottom);       /* iOS >= 11.2 */
}

触摸目标:可点击元素最小 88rpx × 88rpx(44px)。

反模式

反模式正确做法
onMounted 空函数直接删除
computed(() => someRef.value) 纯透传直接用 someRef
页面内定义 formatBytes 等通用函数提取到 utils/
相同逻辑在多个页面重复(倒计时、导航点击)提取为 composable
type X = Y 无约束别名直接使用原类型
接口字段完全重复(FormItem 相同)合并为一个或 type Item = Form
checkLogin 函数 40+ 行提取 getCurrentPagePath,简化主函数

自查清单

  • [ ] 方法命名符合规范(handle/load/fetch 前缀)
  • [ ] 布尔值 is/has/should 前缀
  • [ ] 重复逻辑已提取为 composable
  • [ ] 通用函数已提取到 utils
  • [ ] 重复接口已合并
  • [ ] 无空函数、死代码

基于 MIT 许可发布 · 由 ❤️ 和 ☕ 驱动 · 支持作者