# Vue实战项目

# 项目结构

project/
├── src/
│   ├── assets/          # 静态资源
│   ├── components/      # 组件
│   │   ├── common/      # 通用组件
│   │   └── business/    # 业务组件
│   ├── views/           # 页面
│   ├── router/          # 路由配置
│   ├── store/           # 状态管理
│   │   ├── modules/     # 模块化store
│   │   └── index.js
│   ├── api/            # API接口
│   ├── utils/           # 工具函数
│   ├── styles/         # 样式文件
│   ├── App.vue
│   └── main.js
├── public/
└── package.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 完整示例:Todo应用

# 组件设计

<!-- TodoItem.vue -->
<template>
  <div class="todo-item" :class="{ completed: todo.completed }">
    <input
      type="checkbox"
      :checked="todo.completed"
      @change="toggleTodo"
    />
    <span class="todo-text">{{ todo.text }}</span>
    <button @click="deleteTodo">删除</button>
  </div>
</template>

<script>
export default {
  name: 'TodoItem',
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  methods: {
    toggleTodo() {
      this.$emit('toggle', this.todo.id)
    },
    deleteTodo() {
      this.$emit('delete', this.todo.id)
    }
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 状态管理

// store/modules/todos.js
export default {
  namespaced: true,
  state: {
    todos: []
  },
  mutations: {
    ADD_TODO(state, todo) {
      state.todos.push(todo)
    },
    TOGGLE_TODO(state, id) {
      const todo = state.todos.find(t => t.id === id)
      if (todo) {
        todo.completed = !todo.completed
      }
    },
    DELETE_TODO(state, id) {
      state.todos = state.todos.filter(t => t.id !== id)
    }
  },
  actions: {
    addTodo({ commit }, text) {
      const todo = {
        id: Date.now(),
        text,
        completed: false
      }
      commit('ADD_TODO', todo)
    }
  },
  getters: {
    completedTodos: state => state.todos.filter(t => t.completed),
    activeTodos: state => state.todos.filter(t => !t.completed)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# API封装

// api/todos.js
import axios from 'axios'

const api = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000
})

export default {
  getTodos() {
    return api.get('/todos')
  },
  createTodo(todo) {
    return api.post('/todos', todo)
  },
  updateTodo(id, todo) {
    return api.put(`/todos/${id}`, todo)
  },
  deleteTodo(id) {
    return api.delete(`/todos/${id}`)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 最佳实践总结

# 1. 组件设计原则

  • 单一职责: 每个组件只做一件事
  • 可复用性: 提取通用逻辑为组件
  • Props验证: 始终定义props类型
  • 事件命名: 使用kebab-case

# 2. 状态管理策略

  • 组件状态: 仅组件使用的状态放在组件内
  • 共享状态: 使用Vuex管理
  • 服务器状态: 使用Vuex actions处理

# 3. 性能优化

  • v-if vs v-show: 频繁切换用v-show
  • key的使用: 列表使用唯一key
  • 计算属性缓存: 复杂计算使用computed
  • 异步组件: 路由懒加载

# 4. 代码组织

  • 模块化: 按功能拆分模块
  • 命名规范: 统一命名风格
  • 注释文档: 关键逻辑添加注释
  • 类型检查: 使用TypeScript或PropTypes

# 路由与权限

// router/index.js
const routes = [
  { path: '/login', component: Login },
  {
    path: '/admin',
    component: Layout,
    meta: { requiresAuth: true, roles: ['admin'] },
    children: [
      { path: 'users', component: UserList }
    ]
  }
]

router.beforeEach((to, from, next) => {
  const token = store.getters.token
  if (to.meta.requiresAuth && !token) {
    next('/login')
  } else if (to.meta.roles && !to.meta.roles.includes(store.getters.role)) {
    next('/403')
  } else {
    next()
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 请求封装与错误处理

// api/request.js
import axios from 'axios'

const instance = axios.create({
  baseURL: process.env.VUE_APP_BASE_URL,
  timeout: 10000
})

instance.interceptors.request.use(config => {
  config.headers.Authorization = `Bearer ${getToken()}`
  return config
})

instance.interceptors.response.use(
  res => res.data,
  err => {
    if (err.response?.status === 401) {
      clearToken()
      router.push('/login')
    }
    return Promise.reject(err)
  }
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 环境与构建

  • 环境变量:.env、.env.production;VUE_APP_ 前缀可在代码中访问。
  • 生产构建:vue-cli-service build;可配置 splitChunks、cdn、gzip。
  • 部署:静态资源可部署到 CDN;History 模式需服务端 fallback 到 index.html。