Vue 技术栈开发最佳实践与常见避坑指南

Vue.js作为现代前端框架的代表之一,以其简洁的语法、优秀的性能和丰富的生态系统赢得了开发者的青睐。随着Vue 3的发布,Composition API、更好的TypeScript支持、性能优化等新特性为开发带来了更多可能性。

本文章内容为自身项目实践方法总结,希望通过本文章这些项目最佳实践和注意事项,帮助更多的开发者构建高质量、可维护、高性能的Vue应用,提升开发效率和用户体验。

技术栈版本

  • Vue: 3.x
  • Vue Router: 4.x
  • Pinia: 2.x (状态管理)
  • TypeScript: 5.x
  • Vite: 5.x (构建工具)

Vue 3 Composition API最佳实践

1. 响应式数据管理

正确使用响应式API
// ✅ 推荐:使用ref和reactive
import { ref, reactive, computed, watch } from 'vue'

export default {
  setup() {
    // 基本类型使用ref
    const count = ref(0)
    const message = ref('Hello Vue 3')
    
    // 对象类型使用reactive
    const state = reactive({
      user: {
        name: 'John',
        age: 25
      },
      settings: {
        theme: 'dark',
        language: 'zh-CN'
      }
    })
    
    // 计算属性
    const doubleCount = computed(() => count.value * 2)
    
    // 侦听器
    watch(count, (newVal, oldVal) => {
      console.log(`Count changed from ${oldVal} to ${newVal}`)
    })
    
    return {
      count,
      message,
      state,
      doubleCount
    }
  }
}
避免响应式陷阱
// ❌ 错误:直接解构reactive对象
const { user, settings } = reactive({
  user: { name: 'John' },
  settings: { theme: 'dark' }
})
// user和settings失去响应性

// ✅ 正确:使用toRefs保持响应性
import { toRefs } from 'vue'
const state = reactive({
  user: { name: 'John' },
  settings: { theme: 'dark' }
})
const { user, settings } = toRefs(state)

// ✅ 或者使用computed
const user = computed(() => state.user)
const settings = computed(() => state.settings)

2. 生命周期管理

正确使用生命周期钩子
import { onMounted, onUnmounted, onBeforeUnmount } from 'vue'

export default {
  setup() {
    let timer: number | null = null
    
    onMounted(() => {
      // 组件挂载后的逻辑
      timer = setInterval(() => {
        console.log('Timer tick')
      }, 1000)
    })
    
    onBeforeUnmount(() => {
      // 清理定时器,防止内存泄漏
      if (timer) {
        clearInterval(timer)
        timer = null
      }
    })
    
    return {}
  }
}

3. 组合式函数(Composables)

创建可复用的组合式函数
// composables/useCounter.ts
import { ref, computed } from 'vue'

export function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  
  const increment = () => count.value++
  const decrement = () => count.value--
  const reset = () => count.value = initialValue
  
  const doubleCount = computed(() => count.value * 2)
  
  return {
    count: readonly(count),
    increment,
    decrement,
    reset,
    doubleCount
  }
}

// 在组件中使用
export default {
  setup() {
    const { count, increment, decrement, doubleCount } = useCounter(10)
    
    return {
      count,
      increment,
      decrement,
      doubleCount
    }
  }
}
异步数据获取组合式函数
// composables/useApi.ts
import { ref, onMounted } from 'vue'

export function useApi<T>(url: string) {
  const data = ref<T | null>(null)
  const loading = ref(false)
  const error = ref<string | null>(null)
  
  const fetchData = async () => {
    loading.value = true
    error.value = null
    
    try {
      const response = await fetch(url)
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`)
      }
      data.value = await response.json()
    } catch (err) {
      error.value = err instanceof Error ? err.message : 'Unknown error'
    } finally {
      loading.value = false
    }
  }
  
  onMounted(fetchData)
  
  return {
    data: readonly(data),
    loading: readonly(loading),
    error: readonly(error),
    refetch: fetchData
  }
}

组件设计与架构最佳实践

1. 组件设计原则

单一职责原则
<!-- ❌ 错误:组件职责过多 -->
<template>
  <div class="user-profile">
    <div class="user-info">
      <h2>{{ user.name }}</h2>
      <p>{{ user.email }}</p>
    </div>
    <div class="user-actions">
      <button @click="editUser">编辑</button>
      <button @click="deleteUser">删除</button>
    </div>
    <div class="user-posts">
      <h3>用户文章</h3>
      <div v-for="post in posts" :key="post.id">
        {{ post.title }}
      </div>
    </div>
  </div>
</template>

<!-- ✅ 正确:拆分为多个职责单一的组件 -->
<template>
  <div class="user-profile">
    <UserInfo :user="user" />
    <UserActions :user="user" @edit="handleEdit" @delete="handleDelete" />
    <UserPosts :posts="posts" />
  </div>
</template>
组件命名规范
// ✅ 推荐:PascalCase命名
// components/UserProfile.vue
// components/UserInfo.vue
// components/UserActions.vue

// ✅ 推荐:描述性命名
// components/ProductCard.vue (而不是 Card.vue)
// components/OrderSummary.vue (而不是 Summary.vue)

2. Props设计

Props类型定义和验证
<script setup lang="ts">
interface User {
  id: number
  name: string
  email: string
  avatar?: string
}

interface Props {
  user: User
  showActions?: boolean
  size?: 'small' | 'medium' | 'large'
}

const props = withDefaults(defineProps<Props>(), {
  showActions: true,
  size: 'medium'
})

// 运行时验证
const props = defineProps({
  user: {
    type: Object as PropType<User>,
    required: true,
    validator: (value: User) => {
      return value.id && value.name && value.email
    }
  },
  showActions: {
    type: Boolean,
    default: true
  },
  size: {
    type: String as PropType<'small' | 'medium' | 'large'>,
    default: 'medium'
  }
})
</script>

3. 事件设计

事件命名和类型定义
<script setup lang="ts">
// 定义事件类型
interface Emits {
  (e: 'update:user', user: User): void
  (e: 'delete', id: number): void
  (e: 'edit', user: User): void
}

const emit = defineEmits<Emits>()

// 或者使用运行时定义
const emit = defineEmits({
  'update:user': (user: User) => typeof user === 'object',
  'delete': (id: number) => typeof id === 'number',
  'edit': (user: User) => typeof user === 'object'
})

const handleEdit = (user: User) => {
  emit('edit', user)
}

const handleDelete = (id: number) => {
  emit('delete', id)
}
</script>

4. 插槽设计

具名插槽和作用域插槽
<!-- BaseCard.vue -->
<template>
  <div class="card">
    <header v-if="$slots.header" class="card-header">
      <slot name="header" :title="title" />
    </header>
    
    <main class="card-body">
      <slot :data="data" />
    </main>
    
    <footer v-if="$slots.footer" class="card-footer">
      <slot name="footer" :actions="actions" />
    </footer>
  </div>
</template>

<script setup lang="ts">
interface Props {
  title: string
  data: any
  actions?: string[]
}

defineProps<Props>()
</script>

<!-- 使用示例 -->
<template>
  <BaseCard title="用户信息" :data="user" :actions="['编辑', '删除']">
    <template #header="{ title }">
      <h2>{{ title }}</h2>
    </template>
    
    <template #default="{ data }">
      <p>姓名: {{ data.name }}</p>
      <p>邮箱: {{ data.email }}</p>
    </template>
    
    <template #footer="{ actions }">
      <button v-for="action in actions" :key="action">
        {{ action }}
      </button>
    </template>
  </BaseCard>
</template>

性能优化与内存管理

1. 组件性能优化

合理使用v-if和v-show
<template>
  <!-- ✅ 推荐:频繁切换使用v-show -->
  <div v-show="isVisible" class="modal">
    <!-- 模态框内容 -->
  </div>
  
  <!-- ✅ 推荐:条件很少改变使用v-if -->
  <div v-if="user.isAdmin" class="admin-panel">
    <!-- 管理员面板 -->
  </div>
</template>
列表渲染优化
<template>
  <!-- ✅ 推荐:使用key优化列表渲染 -->
  <div v-for="item in items" :key="item.id" class="item">
    {{ item.name }}
  </div>
  
  <!-- ✅ 推荐:大列表使用虚拟滚动 -->
  <VirtualList
    :items="largeList"
    :item-height="50"
    :container-height="400"
  >
    <template #default="{ item }">
      <div class="list-item">{{ item.name }}</div>
    </template>
  </VirtualList>
</template>

2. 计算属性优化

避免在模板中使用复杂计算
<template>
  <!-- ❌ 错误:在模板中进行复杂计算 -->
  <div>
    {{ expensiveCalculation(data) }}
  </div>
  
  <!-- ✅ 正确:使用计算属性 -->
  <div>
    {{ computedResult }}
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'

const props = defineProps<{
  data: any[]
}>()

// 计算属性会被缓存,只有依赖变化时才重新计算
const computedResult = computed(() => {
  return props.data.reduce((sum, item) => {
    return sum + item.value
  }, 0)
})

// ❌ 错误:在setup中定义函数
const expensiveCalculation = (data: any[]) => {
  // 每次渲染都会执行
  return data.reduce((sum, item) => sum + item.value, 0)
}
</script>

3. 内存泄漏防护

事件监听器清理
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue'

export default {
  setup() {
    const handleResize = () => {
      console.log('Window resized')
    }
    
    const handleScroll = () => {
      console.log('Page scrolled')
    }
    
    onMounted(() => {
      window.addEventListener('resize', handleResize)
      document.addEventListener('scroll', handleScroll)
    })
    
    onUnmounted(() => {
      // ✅ 重要:清理事件监听器
      window.removeEventListener('resize', handleResize)
      document.removeEventListener('scroll', handleScroll)
    })
  }
}
</script>
定时器清理
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'

export default {
  setup() {
    const count = ref(0)
    let timer: number | null = null
    
    onMounted(() => {
      timer = setInterval(() => {
        count.value++
      }, 1000)
    })
    
    onUnmounted(() => {
      // ✅ 重要:清理定时器
      if (timer) {
        clearInterval(timer)
        timer = null
      }
    })
    
    return { count }
  }
}
</script>

4. 懒加载和代码分割

路由懒加载
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      name: 'Home',
      component: () => import('@/views/Home.vue')
    },
    {
      path: '/about',
      name: 'About',
      component: () => import('@/views/About.vue')
    },
    {
      path: '/user/:id',
      name: 'User',
      component: () => import('@/views/User.vue')
    }
  ]
})

export default router
组件懒加载
<template>
  <div>
    <Suspense>
      <template #default>
        <AsyncComponent />
      </template>
      <template #fallback>
        <div>Loading...</div>
      </template>
    </Suspense>
  </div>
</template>

<script setup lang="ts">
import { defineAsyncComponent } from 'vue'

// 异步组件
const AsyncComponent = defineAsyncComponent(() => 
  import('@/components/HeavyComponent.vue')
)

// 带加载状态的异步组件
const AsyncComponentWithLoading = defineAsyncComponent({
  loader: () => import('@/components/HeavyComponent.vue'),
  loadingComponent: LoadingComponent,
  errorComponent: ErrorComponent,
  delay: 200,
  timeout: 3000
})
</script>

状态管理与数据流

1. Pinia状态管理

Store设计
// stores/user.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

interface User {
  id: number
  name: string
  email: string
  avatar?: string
}

export const useUserStore = defineStore('user', () => {
  // 状态
  const currentUser = ref<User | null>(null)
  const users = ref<User[]>([])
  const loading = ref(false)
  const error = ref<string | null>(null)
  
  // 计算属性
  const isLoggedIn = computed(() => !!currentUser.value)
  const userCount = computed(() => users.value.length)
  
  // 操作
  const setCurrentUser = (user: User) => {
    currentUser.value = user
  }
  
  const addUser = (user: User) => {
    users.value.push(user)
  }
  
  const removeUser = (id: number) => {
    const index = users.value.findIndex(user => user.id === id)
    if (index > -1) {
      users.value.splice(index, 1)
    }
  }
  
  const fetchUsers = async () => {
    loading.value = true
    error.value = null
    
    try {
      const response = await fetch('/api/users')
      const data = await response.json()
      users.value = data
    } catch (err) {
      error.value = err instanceof Error ? err.message : 'Failed to fetch users'
    } finally {
      loading.value = false
    }
  }
  
  return {
    // 状态
    currentUser,
    users,
    loading,
    error,
    // 计算属性
    isLoggedIn,
    userCount,
    // 操作
    setCurrentUser,
    addUser,
    removeUser,
    fetchUsers
  }
})
在组件中使用Store
<template>
  <div>
    <div v-if="userStore.loading">Loading...</div>
    <div v-else-if="userStore.error">{{ userStore.error }}</div>
    <div v-else>
      <h2>Users ({{ userStore.userCount }})</h2>
      <div v-for="user in userStore.users" :key="user.id">
        {{ user.name }} - {{ user.email }}
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { useUserStore } from '@/stores/user'
import { onMounted } from 'vue'

const userStore = useUserStore()

onMounted(() => {
  userStore.fetchUsers()
})
</script>

2. 数据流设计

单向数据流
<!-- 父组件 -->
<template>
  <div>
    <UserList 
      :users="users" 
      @user-selected="handleUserSelected"
      @user-deleted="handleUserDeleted"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import UserList from './UserList.vue'

const users = ref([
  { id: 1, name: 'John', email: 'john@example.com' },
  { id: 2, name: 'Jane', email: 'jane@example.com' }
])

const handleUserSelected = (user: User) => {
  console.log('User selected:', user)
}

const handleUserDeleted = (userId: number) => {
  users.value = users.value.filter(user => user.id !== userId)
}
</script>

<!-- 子组件 -->
<template>
  <div>
    <div 
      v-for="user in users" 
      :key="user.id"
      @click="$emit('user-selected', user)"
    >
      {{ user.name }}
      <button @click.stop="$emit('user-deleted', user.id)">
        Delete
      </button>
    </div>
  </div>
</template>

<script setup lang="ts">
interface User {
  id: number
  name: string
  email: string
}

interface Props {
  users: User[]
}

defineProps<Props>()

const emit = defineEmits<{
  'user-selected': [user: User]
  'user-deleted': [userId: number]
}>()
</script>

工程化与构建优化

1. 项目结构

推荐的项目结构
src/
├── components/          # 公共组件
│   ├── base/           # 基础组件
│   ├── business/       # 业务组件
│   └── layout/         # 布局组件
├── views/              # 页面组件
├── composables/        # 组合式函数
├── stores/             # Pinia stores
├── router/             # 路由配置
├── utils/              # 工具函数
├── types/              # TypeScript类型定义
├── assets/             # 静态资源
├── styles/             # 样式文件
└── main.ts             # 应用入口

2. Vite配置优化

vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

export default defineConfig({
  plugins: [vue()],
  
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
      '@components': resolve(__dirname, 'src/components'),
      '@views': resolve(__dirname, 'src/views'),
      '@utils': resolve(__dirname, 'src/utils'),
      '@stores': resolve(__dirname, 'src/stores')
    }
  },
  
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['vue', 'vue-router', 'pinia'],
          utils: ['lodash-es', 'dayjs']
        }
      }
    },
    
    // 代码分割
    chunkSizeWarningLimit: 1000,
    
    // 压缩配置
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    }
  },
  
  // 开发服务器配置
  server: {
    port: 3000,
    open: true,
    cors: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

3. 环境配置

环境变量管理
// .env.development
VITE_APP_TITLE=开发环境
VITE_API_BASE_URL=http://localhost:8080
VITE_APP_DEBUG=true

// .env.production
VITE_APP_TITLE=生产环境
VITE_API_BASE_URL=https://api.example.com
VITE_APP_DEBUG=false

// utils/env.ts
export const config = {
  title: import.meta.env.VITE_APP_TITLE,
  apiBaseUrl: import.meta.env.VITE_API_BASE_URL,
  isDebug: import.meta.env.VITE_APP_DEBUG === 'true'
}

测试与代码质量保证

1. 单元测试

组件测试
// tests/components/UserCard.test.ts
import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import UserCard from '@/components/UserCard.vue'

describe('UserCard', () => {
  it('renders user information correctly', () => {
    const user = {
      id: 1,
      name: 'John Doe',
      email: 'john@example.com'
    }
    
    const wrapper = mount(UserCard, {
      props: { user }
    })
    
    expect(wrapper.text()).toContain('John Doe')
    expect(wrapper.text()).toContain('john@example.com')
  })
  
  it('emits edit event when edit button is clicked', async () => {
    const user = {
      id: 1,
      name: 'John Doe',
      email: 'john@example.com'
    }
    
    const wrapper = mount(UserCard, {
      props: { user }
    })
    
    await wrapper.find('[data-testid="edit-button"]').trigger('click')
    
    expect(wrapper.emitted('edit')).toBeTruthy()
    expect(wrapper.emitted('edit')?.[0]).toEqual([user])
  })
})
组合式函数测试
// tests/composables/useCounter.test.ts
import { describe, it, expect } from 'vitest'
import { useCounter } from '@/composables/useCounter'

describe('useCounter', () => {
  it('should initialize with default value', () => {
    const { count } = useCounter()
    expect(count.value).toBe(0)
  })
  
  it('should initialize with custom value', () => {
    const { count } = useCounter(10)
    expect(count.value).toBe(10)
  })
  
  it('should increment count', () => {
    const { count, increment } = useCounter(0)
    increment()
    expect(count.value).toBe(1)
  })
  
  it('should decrement count', () => {
    const { count, decrement } = useCounter(5)
    decrement()
    expect(count.value).toBe(4)
  })
})

2. 代码质量工具

ESLint配置
// .eslintrc.js
module.exports = {
  root: true,
  env: {
    node: true,
    browser: true,
    es2022: true
  },
  extends: [
    'plugin:vue/vue3-recommended',
    '@vue/typescript/recommended',
    '@vue/prettier'
  ],
  parserOptions: {
    ecmaVersion: 2022,
    sourceType: 'module'
  },
  rules: {
    'vue/component-name-in-template-casing': ['error', 'PascalCase'],
    'vue/component-definition-name-casing': ['error', 'PascalCase'],
    'vue/multi-word-component-names': 'off',
    '@typescript-eslint/no-unused-vars': 'error',
    '@typescript-eslint/no-explicit-any': 'warn'
  }
}
Prettier配置
// .prettierrc
{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "none",
  "printWidth": 100,
  "endOfLine": "lf"
}

安全性与部署注意事项

1. 安全最佳实践

XSS防护
<template>
  <!-- ❌ 危险:直接渲染用户输入 -->
  <div v-html="userInput"></div>
  
  <!-- ✅ 安全:使用文本插值 -->
  <div>{{ userInput }}</div>
  
  <!-- ✅ 安全:如果需要HTML,使用安全的HTML解析器 -->
  <div v-html="sanitizedHtml"></div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import DOMPurify from 'dompurify'

const props = defineProps<{
  userInput: string
}>()

const sanitizedHtml = computed(() => {
  return DOMPurify.sanitize(props.userInput)
})
</script>
CSRF防护
// utils/request.ts
import axios from 'axios'

const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10000
})

// 请求拦截器
request.interceptors.request.use(
  (config) => {
    // 添加CSRF token
    const token = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')
    if (token) {
      config.headers['X-CSRF-TOKEN'] = token
    }
    
    // 添加认证token
    const authToken = localStorage.getItem('auth_token')
    if (authToken) {
      config.headers.Authorization = `Bearer ${authToken}`
    }
    
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

export default request

2. 部署配置

Docker配置
# Dockerfile
FROM node:18-alpine as build

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Nginx配置
# nginx.conf
server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    # 启用gzip压缩
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # SPA路由支持
    location / {
        try_files $uri $uri/ /index.html;
    }

    # API代理
    location /api/ {
        proxy_pass http://backend:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

团队协作与开发规范

1. Git工作流

分支策略
# 主分支
main          # 生产环境分支
develop       # 开发环境分支

# 功能分支
feature/user-auth     # 用户认证功能
feature/payment       # 支付功能

# 修复分支
hotfix/critical-bug   # 紧急修复
bugfix/login-issue    # 登录问题修复

# 发布分支
release/v1.2.0        # 版本发布
提交规范
# 提交信息格式
<type>(<scope>): <subject>

# 类型
feat:     新功能
fix:      修复bug
docs:     文档更新
style:    代码格式调整
refactor: 代码重构
test:     测试相关
chore:    构建过程或辅助工具的变动

# 示例
feat(auth): add user login functionality
fix(router): resolve navigation issue
docs(readme): update installation guide

2. 代码审查

审查清单
## 代码审查清单

### 功能正确性
- [ ] 功能是否按需求实现
- [ ] 边界条件是否处理
- [ ] 错误处理是否完善

### 代码质量
- [ ] 代码是否遵循项目规范
- [ ] 是否有重复代码
- [ ] 变量命名是否清晰
- [ ] 函数是否单一职责

### 性能考虑
- [ ] 是否有性能问题
- [ ] 内存泄漏风险
- [ ] 不必要的重渲染

### 安全性
- [ ] XSS防护
- [ ] 输入验证
- [ ] 敏感信息处理

### 测试
- [ ] 单元测试是否完整
- [ ] 测试覆盖率是否足够
- [ ] 集成测试是否通过

3. 文档规范

组件文档
<!-- UserCard.vue -->
<template>
  <div class="user-card">
    <!-- 组件内容 -->
  </div>
</template>

<script setup lang="ts">
/**
 * 用户卡片组件
 * 
 * @description 用于显示用户基本信息的卡片组件
 * @author 开发者姓名
 * @since 1.0.0
 */

interface User {
  /** 用户ID */
  id: number
  /** 用户姓名 */
  name: string
  /** 用户邮箱 */
  email: string
  /** 用户头像URL */
  avatar?: string
}

interface Props {
  /** 用户信息 */
  user: User
  /** 是否显示操作按钮 */
  showActions?: boolean
  /** 卡片尺寸 */
  size?: 'small' | 'medium' | 'large'
}

const props = withDefaults(defineProps<Props>(), {
  showActions: true,
  size: 'medium'
})

/**
 * 编辑用户事件
 */
const emit = defineEmits<{
  /** 编辑用户时触发 */
  edit: [user: User]
  /** 删除用户时触发 */
  delete: [userId: number]
}>()
</script>

总结与建议

1. 核心最佳实践总结

开发规范
  • 使用TypeScript:提供类型安全和更好的开发体验
  • 遵循组件设计原则:单一职责、高内聚低耦合
  • 合理使用Composition API:提高代码复用性和可维护性
  • 性能优化:懒加载、虚拟滚动、内存管理
  • 代码质量:ESLint、Prettier、单元测试
架构设计
  • 模块化设计:清晰的项目结构和组件划分
  • 状态管理:使用Pinia进行集中式状态管理
  • 路由管理:合理的路由设计和懒加载
  • 工程化:完善的构建配置和部署流程

2. 常见陷阱与避免方法

性能陷阱
// ❌ 避免:在模板中使用复杂计算
<template>
  <div>{{ expensiveCalculation(data) }}</div>
</template>

// ✅ 正确:使用计算属性
<template>
  <div>{{ computedResult }}</div>
</template>

<script setup lang="ts">
const computedResult = computed(() => expensiveCalculation(data))
</script>
内存泄漏陷阱
// ❌ 避免:忘记清理事件监听器
onMounted(() => {
  window.addEventListener('resize', handleResize)
})

// ✅ 正确:在组件卸载时清理
onMounted(() => {
  window.addEventListener('resize', handleResize)
})

onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
})
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

立方世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值