Vue.js 全栈知识点费曼学习法指南

Vue.js 全栈知识点费曼学习法指南

🧠 费曼学习法核心原则

如果你不能简单地解释一个概念,说明你还没有真正理解它。

这份指南将用最简单易懂的语言,帮你彻底掌握Vue.js生态系统的所有核心知识点。


📚 目录结构

第一部分:Vue.js 核心基础

  1. Vue.js 是什么?
  2. 响应式系统
  3. 模板语法
  4. 组件系统
  5. 生命周期

第二部分:Vue.js 进阶特性

  1. 指令系统
  2. API 风格对比
  3. 单文件组件
  4. 组合式 API 深入

第三部分:Vue.js 生态系统

  1. 路由管理 Vue Router
  2. 状态管理 Vuex vs Pinia
  3. 构建工具 Vite

第一部分:Vue.js 核心基础

1. Vue.js 是什么?

简单理解

Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架,就像智能家居的控制中心

生活例子:

  • 想象你家里有很多电器:灯、空调、电视
  • 传统方式:你需要逐个手动控制每个设备
  • Vue方式:一个智能控制中心,你只需要说出需求,它自动协调所有设备
核心特点

1. 渐进式框架 Vue 的设计非常注重灵活性和"可以被逐步集成"这个特点

简单理解: 就像学游泳一样

  • 🏊‍♀️ 浅水区:给现有网页加点交互(无需构建工具)
  • 🏊‍♂️ 深水区:构建完整的单页应用
  • 🏊‍♀️ 比赛级:全栈开发、服务器渲染

2. 声明式渲染 传统命令式: "先做这个,再做那个,然后..." Vue声明式: "我想要这个结果",Vue自动处理过程

scss 复制代码
// 你只需要声明想要什么
<button @click="count++">点击次数: {{ count }}</button>

3. 响应式系统 简单理解: 数据和界面的"魔法连接"

  • 数据变化 → 界面自动更新
  • 就像Excel表格,改变A1,使用A1的公式会自动重新计算

2. 响应式系统

什么是响应式?

响应性是一种可以使我们声明式地处理变化的编程范式

生活例子:

  • 温度计和空调:温度计检测到温度变化,空调自动调整
  • 银行账户和ATM显示:账户余额变化,ATM屏幕自动更新显示
Vue的响应式原理

用厨房类比:

scss 复制代码
数据(食材) → Vue响应式系统(智能厨房) → 界面(菜品)

核心概念:

1. ref() - 基本数据类型的响应式

js 复制代码
import { ref } from 'vue'
const count = ref(0)  // 包装成响应式

// 简单理解:给数据加个"监控器"

2. reactive() - 对象的响应式

js 复制代码
import { reactive } from 'vue'
const state = reactive({
  name: '张三',
  age: 25
})

// 简单理解:给整个对象加"智能监控"

记忆技巧:

  • ref = 单个值的"保险箱"
  • reactive = 整个对象的"智能监控系统"
响应式的"魔法"

原理简化版:

  1. 依赖收集:Vue记住"谁在用这个数据"
  2. 变化检测:数据变化时,Vue知道了
  3. 自动更新:通知所有使用这个数据的地方更新

实际例子:

js 复制代码
// 1. 创建响应式数据
const message = ref('Hello')

// 2. 模板中使用
<p>{{ message }}</p>  // Vue记住:这个p标签用了message

// 3. 数据变化
message.value = 'World'  // Vue自动更新p标签内容

3. 模板语法

插值语法({{ }})

简单理解: 就像模板填空题

html 复制代码
<!-- 文本插值 -->
<p>Hello {{ name }}!</p>

<!-- JavaScript表达式 -->
<p>{{ number + 1 }}</p>
<p>{{ ok ? 'YES' : 'NO' }}</p>

生活例子:

  • 就像写信:"亲爱的{{ 收件人姓名 }},..."
  • Vue会自动把{{ }}里的内容替换成实际值
指令基础

指令 = 给HTML元素的"特殊指令"

1. v-bind - 绑定属性

html 复制代码
<!-- 传统HTML -->
<img src="固定路径.jpg">

<!-- Vue方式 -->
<img v-bind:src="动态路径">
<!-- 简写 -->
<img :src="动态路径">

2. v-on - 事件监听

html 复制代码
<!-- 传统方式 -->
<button onclick="doSomething()">点击</button>

<!-- Vue方式 -->
<button v-on:click="doSomething">点击</button>
<!-- 简写 -->
<button @click="doSomething">点击</button>

3. v-if - 条件渲染

html 复制代码
<p v-if="isVisible">只有条件为真才显示</p>

4. v-for - 列表渲染

html 复制代码
<li v-for="item in list" :key="item.id">
  {{ item.name }}
</li>

5. v-model - 双向绑定

html 复制代码
<input v-model="message">
<p>{{ message }}</p>  <!-- 输入框和文字会同步变化 -->

记忆技巧:

  • v-bind = 单向传递(数据→界面)
  • v-model = 双向同步(数据↔界面)
  • v-on = 监听事件
  • v-if = 条件显示
  • v-for = 循环列表

4. 组件系统

什么是组件?

简单理解: 组件是可复用的 Vue 实例,就像乐高积木块

生活例子:

  • 汽车 = 引擎组件 + 轮胎组件 + 座椅组件
  • 网页 = 头部组件 + 导航组件 + 内容组件 + 底部组件
组件的基本结构
html 复制代码
<template>
  <!-- 组件的HTML结构(身体) -->
  <div class="my-component">
    <h2>{{ title }}</h2>
    <button @click="handleClick">点击</button>
  </div>
</template>

<script setup>
// 组件的逻辑(大脑)
import { ref } from 'vue'

const title = ref('我是一个组件')

function handleClick() {
  title.value = '被点击了!'
}
</script>

<style scoped>
/* 组件的样式(衣服) */
.my-component {
  padding: 20px;
  border: 1px solid #ccc;
}
</style>
组件通信

1. Props - 父传子 简单理解: 就像父母给孩子零花钱

html 复制代码
<!-- 父组件 -->
<ChildComponent :money="100" :message="'好好学习'" />

<!-- 子组件 -->
<script setup>
// 接收props
defineProps({
  money: Number,
  message: String
})
</script>

2. Emit - 子传父 简单理解: 就像孩子向父母报告

html 复制代码
<!-- 子组件 -->
<script setup>
const emit = defineEmits(['report'])

function reportToParent() {
  emit('report', '我考了100分!')
}
</script>

<!-- 父组件 -->
<ChildComponent @report="handleReport" />

3. 插槽 (Slots) - 内容分发 简单理解: 就像预留的空位

html 复制代码
<!-- 组件定义 -->
<template>
  <div class="card">
    <h3>{{ title }}</h3>
    <slot></slot>  <!-- 这里是预留空位 -->
  </div>
</template>

<!-- 使用组件 -->
<Card title="用户信息">
  <p>这些内容会插入到slot位置</p>
</Card>

5. 生命周期

什么是生命周期?

简单理解: 组件从出生到死亡的整个过程,就像人的生命周期

生活例子:

js 复制代码
婴儿出生 → 上学 → 工作 → 结婚 → 退休 → 去世
   ↓        ↓      ↓      ↓      ↓      ↓
 created → mounted → updated → ... → unmounted
主要生命周期钩子

选项式 API:

js 复制代码
export default {
  // 1. 组件创建前
  beforeCreate() {
    console.log('组件还没出生')
  },
  
  // 2. 组件创建完成
  created() {
    console.log('组件出生了,可以发送请求获取数据')
  },
  
  // 3. 组件挂载前
  beforeMount() {
    console.log('准备上学(挂载到页面)')
  },
  
  // 4. 组件挂载完成
  mounted() {
    console.log('已经在学校了(页面上可见)')
  },
  
  // 5. 组件更新前
  beforeUpdate() {
    console.log('准备考试(数据要变化)')
  },
  
  // 6. 组件更新完成
  updated() {
    console.log('考试结束(页面已更新)')
  },
  
  // 7. 组件销毁前
  beforeUnmount() {
    console.log('准备毕业(组件要被销毁)')
  },
  
  // 8. 组件销毁完成
  unmounted() {
    console.log('已经毕业(组件被销毁)')
  }
}

组合式 API:

js 复制代码
import { onMounted, onUpdated, onUnmounted } from 'vue'

export default {
  setup() {
    onMounted(() => {
      console.log('组件挂载完成')
    })
    
    onUpdated(() => {
      console.log('组件更新完成')
    })
    
    onUnmounted(() => {
      console.log('组件即将销毁')
    })
  }
}

实际应用场景:

  • created/setup:发送HTTP请求获取数据
  • mounted:操作DOM元素、初始化第三方库
  • updated:数据变化后的额外处理
  • unmounted:清理定时器、解绑事件

第二部分:Vue.js 进阶特性

6. 指令系统

内置指令详解

1. v-show vs v-if

v-if:真正的条件渲染

html 复制代码
<p v-if="isVisible">我可能存在也可能不存在</p>
  • 特点 :条件为假时,元素完全不存在
  • 类比:房子要么盖起来,要么根本不盖

v-show:显示/隐藏

html 复制代码
<p v-show="isVisible">我总是存在,只是可能被隐藏</p>
  • 特点 :元素总是存在,只是CSS隐藏
  • 类比:房子盖好了,只是拉上窗帘

选择建议:

  • 频繁切换 → 用 v-show
  • 很少切换 → 用 v-if

2. v-for 列表渲染

html 复制代码
<!-- 遍历数组 -->
<li v-for="(item, index) in fruits" :key="item.id">
  {{ index }} - {{ item.name }}
</li>

<!-- 遍历对象 -->
<li v-for="(value, key) in userInfo" :key="key">
  {{ key }}: {{ value }}
</li>

<!-- 遍历数字 -->
<span v-for="n in 10" :key="n">{{ n }}</span>

重要:为什么需要 key?

  • 类比:给每个学生一个学号,方便老师识别
  • Vue用key来识别每个元素,提高更新效率

3. v-model 双向绑定

html 复制代码
<!-- 文本输入 -->
<input v-model="message">

<!-- 复选框 -->
<input type="checkbox" v-model="checked">

<!-- 单选框 -->
<input type="radio" value="A" v-model="picked">
<input type="radio" value="B" v-model="picked">

<!-- 选择框 -->
<select v-model="selected">
  <option value="A">选项A</option>
  <option value="B">选项B</option>
</select>
自定义指令

简单理解: 给HTML元素添加自定义超能力

js 复制代码
// 自动聚焦指令
app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})

// 使用
<input v-focus>

实际例子:

js 复制代码
// 点击外部关闭指令
app.directive('click-outside', {
  mounted(el, binding) {
    el.clickOutsideEvent = function(event) {
      if (!(el === event.target || el.contains(event.target))) {
        binding.value()
      }
    }
    document.addEventListener('click', el.clickOutsideEvent)
  },
  unmounted(el) {
    document.removeEventListener('click', el.clickOutsideEvent)
  }
})

// 使用
<div v-click-outside="closeModal">点击外部关闭</div>

7. API 风格对比

Options API vs Composition API

选项式 API(Options API) 选项式 API 以"组件实例"的概念为中心

特点:传统食谱,分类明确

js 复制代码
export default {
  data() {
    return {
      count: 0,
      message: 'Hello'
    }
  },
  methods: {
    increment() {
      this.count++
    }
  },
  computed: {
    doubleCount() {
      return this.count * 2
    }
  },
  mounted() {
    console.log('组件挂载完成')
  }
}

优点:

  • 结构清晰,初学者友好
  • 强制代码组织,不容易乱
  • 类似面向对象编程思维

组合式 API(Composition API) 组合式 API 的核心思想是直接在函数作用域内定义响应式状态变量

特点:自由式烹饪,更灵活

js 复制代码
import { ref, computed, onMounted } from 'vue'

export default {
  setup() {
    // 状态
    const count = ref(0)
    const message = ref('Hello')
    
    // 计算属性
    const doubleCount = computed(() => count.value * 2)
    
    // 方法
    function increment() {
      count.value++
    }
    
    // 生命周期
    onMounted(() => {
      console.log('组件挂载完成')
    })
    
    return {
      count,
      message,
      doubleCount,
      increment
    }
  }
}

优点:

  • 更灵活的代码组织
  • 更好的TypeScript支持
  • 更容易抽取和复用逻辑
更简洁的写法:
js 复制代码
<script setup>
import { ref, computed, onMounted } from 'vue'

// 直接声明,自动暴露给模板
const count = ref(0)
const doubleCount = computed(() => count.value * 2)

function increment() {
count.value++
}

onMounted(() => {
console.log('组件挂载完成')
})
</script>
如何选择?

学习阶段:

  • 新手 → Options API(结构清晰)
  • 有经验 → Composition API(更强大)

项目选择:

  • 简单项目 → Options API
  • 复杂项目、需要TypeScript → Composition API

8. 单文件组件(SFC)

什么是SFC?

Vue 的单文件组件会将一个组件的逻辑 (JavaScript),模板 (HTML) 和样式 (CSS) 封装在同一个文件里

简单理解: 把相关的东西放在一起,就像个人档案袋

  • 成绩单(模板)
  • 简历(逻辑)
  • 照片(样式)
SFC的结构
js 复制代码
<template>
  <!-- 模板部分:组件的HTML结构 -->
  <div class="my-component">
    <h1>{{ title }}</h1>
    <button @click="changeTitle">改变标题</button>
  </div>
</template>

<script>
// 脚本部分:组件的逻辑
export default {
  data() {
    return {
      title: '我是标题'
    }
  },
  methods: {
    changeTitle() {
      this.title = '标题被改变了!'
    }
  }
}
</script>

<style scoped>
/* 样式部分:组件的CSS */
.my-component {
  padding: 20px;
  background-color: #f0f0f0;
}

h1 {
  color: blue;
}
</style>
样式作用域

scoped 样式:

css 复制代码
<style scoped>
/* 只影响当前组件 */
.title {
  color: red;
}
</style>

全局样式:

css 复制代码
<style>
/* 影响整个应用 */
.global-class {
  font-size: 16px;
}
</style>

CSS Modules:

js 复制代码
<template>
  <div :class="$style.wrapper">
    <h1 :class="$style.title">标题</h1>
  </div>
</template>

<style module>
.wrapper {
  padding: 20px;
}

.title {
  color: blue;
}
</style>
预处理器支持

使用 Sass:

js 复制代码
<style lang="scss" scoped>
$primary-color: #007bff;

.my-component {
  background-color: $primary-color;
  
  .title {
    color: white;
    
    &:hover {
      opacity: 0.8;
    }
  }
}
</style>

使用 TypeScript:

js 复制代码
<script setup lang="ts">
interface User {
  id: number
  name: string
}

const user: User = {
  id: 1,
  name: 'John'
}
</script>

9. 组合式 API 深入

ref 和 reactive 的选择

ref:基本类型和单一值

js 复制代码
import { ref } from 'vue'

const count = ref(0)
const message = ref('Hello')
const isVisible = ref(true)

// 使用时需要 .value
count.value++
console.log(message.value)

reactive:对象和复杂数据

js 复制代码
import { reactive } from 'vue'

const state = reactive({
  count: 0,
  user: {
    name: 'John',
    age: 25
  }
})

// 直接使用,无需 .value
state.count++
state.user.name = 'Jane'

选择原则:

  • 基本类型(string, number, boolean)→ ref
  • 对象、数组 → reactiveref
计算属性 computed

简单理解: Excel中的公式单元格,依赖变化自动重新计算

js 复制代码
import { ref, computed } from 'vue'

const firstName = ref('张')
const lastName = ref('三')

// 计算属性:自动拼接姓名
const fullName = computed(() => {
  return firstName.value + lastName.value
})

// 可写计算属性
const fullNameWritable = computed({
  get() {
    return firstName.value + lastName.value
  },
  set(value) {
    [firstName.value, lastName.value] = value.split('')
  }
})
侦听器 watch

简单理解: 数据的保镖,数据一变化就执行动作

js 复制代码
import { ref, watch } from 'vue'

const count = ref(0)
const message = ref('Hello')

// 侦听单个值
watch(count, (newValue, oldValue) => {
  console.log(`count从 ${oldValue} 变为 ${newValue}`)
})

// 侦听多个值
watch([count, message], ([newCount, newMessage], [oldCount, oldMessage]) => {
  console.log('count或message发生了变化')
})

// 立即执行
watch(count, (newValue) => {
  console.log('立即执行,当前值:', newValue)
}, { immediate: true })

// 深度监听
const user = ref({ name: 'John', age: 25 })
watch(user, (newUser) => {
  console.log('user对象发生了变化')
}, { deep: true })
watchEffect

简单理解: 自动侦听所有用到的响应式数据

js 复制代码
import { ref, watchEffect } from 'vue'

const count = ref(0)
const message = ref('Hello')

// 自动侦听函数内用到的所有响应式数据
watchEffect(() => {
  console.log(`count是${count.value},message是${message.value}`)
  // 当count或message变化时,这个函数会自动重新执行
})
组合函数(Composables)

简单理解: 把相关逻辑打包成可重用的函数

js 复制代码
// composables/useCounter.js
import { ref } from 'vue'

export function useCounter(initialValue = 0) {
  const count = ref(initialValue)
  
  function increment() {
    count.value++
  }
  
  function decrement() {
    count.value--
  }
  
  function reset() {
    count.value = initialValue
  }
  
  return {
    count,
    increment,
    decrement,
    reset
  }
}

// 在组件中使用
<script setup>
import { useCounter } from '@/composables/useCounter'

const { count, increment, decrement, reset } = useCounter(10)
</script>

常见的组合函数:

js 复制代码
// useLocalStorage - 持久化存储
export function useLocalStorage(key, defaultValue) {
  const storedValue = localStorage.getItem(key)
  const value = ref(storedValue ? JSON.parse(storedValue) : defaultValue)
  
  watch(value, (newValue) => {
    localStorage.setItem(key, JSON.stringify(newValue))
  }, { deep: true })
  
  return value
}

// useFetch - 数据获取
export function useFetch(url) {
  const data = ref(null)
  const loading = ref(false)
  const error = ref(null)
  
  async function fetchData() {
    loading.value = true
    try {
      const response = await fetch(url)
      data.value = await response.json()
    } catch (err) {
      error.value = err
    } finally {
      loading.value = false
    }
  }
  
  fetchData()
  
  return { data, loading, error, refetch: fetchData }
}

第三部分:Vue.js 生态系统

10. 路由管理 Vue Router

什么是路由?

简单理解: 网站的导航系统,就像商场的楼层指引

生活例子:

  • 你想去商场的不同楼层(页面)
  • 电梯/楼梯(路由器)带你到指定楼层
  • 楼层指示牌(URL)告诉你当前位置
基本使用

1. 安装和配置

js 复制代码
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

2. 在main.js中使用

js 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

3. 在组件中使用

js 复制代码
<template>
  <div>
    <!-- 导航链接 -->
    <router-link to="/">首页</router-link>
    <router-link to="/about">关于</router-link>
    
    <!-- 页面内容显示区 -->
    <router-view></router-view>
  </div>
</template>
动态路由

路径参数:

js 复制代码
// 路由配置
{
  path: '/user/:id',
  component: User
}

// 组件中获取参数
<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()
console.log(route.params.id) // 获取用户ID
</script>

查询参数:

scss 复制代码
// URL: /search?keyword=vue&page=1
const route = useRoute()
console.log(route.query.keyword) // 'vue'
console.log(route.query.page)    // '1'
编程式导航
js 复制代码
import { useRouter } from 'vue-router'

const router = useRouter()

// 跳转到指定路径
router.push('/about')

// 跳转并传参
router.push({ name: 'User', params: { id: 123 } })

// 后退
router.back()

// 前进
router.forward()

// 替换当前页面(不会产生历史记录)
router.replace('/login')
路由守卫

简单理解: 路口的保安,检查是否允许通过

js 复制代码
// 全局前置守卫
router.beforeEach((to, from, next) => {
  // 检查是否需要登录
  if (to.meta.requiresAuth && !isLoggedIn) {
    next('/login') // 重定向到登录页
  } else {
    next() // 允许通过
  }
})

// 路由配置中的元信息
{
  path: '/admin',
  component: Admin,
  meta: { requiresAuth: true }
}
嵌套路由

简单理解: 页面中的子页面

js 复制代码
// 路由配置
{
  path: '/user',
  component: User,
  children: [
    {
      path: 'profile',  // /user/profile
      component: UserProfile
    },
    {
      path: 'settings', // /user/settings
      component: UserSettings
    }
  ]
}
js 复制代码
<!-- User.vue -->
<template>
  <div>
    <h2>用户中心</h2>
    <router-link to="/user/profile">个人资料</router-link>
    <router-link to="/user/settings">账户设置</router-link>
    
    <!-- 子页面显示区 -->
    <router-view></router-view>
  </div>
</template>

11. 状态管理 Vuex vs Pinia

为什么需要状态管理?

简单理解: 多个组件需要共享数据时的解决方案

生活例子:

  • 没有状态管理:每个房间都有自己的温度计,互不相通
  • 有状态管理:整栋楼有一个中央控制系统,各个房间共享信息
Vuex(传统方案)

核心概念:

复制代码
State(状态) → 数据仓库
Getters(获取器) → 数据的计算属性  
Mutations(变更) → 同步修改数据的方法
Actions(动作) → 异步操作和业务逻辑

基本使用:

js 复制代码
// store/index.js
import { createStore } from 'vuex'

export default createStore({
  state: {
    count: 0,
    user: null
  },
  
  getters: {
    doubleCount: state => state.count * 2
  },
  
  mutations: {
    INCREMENT(state) {
      state.count++
    },
    SET_USER(state, user) {
      state.user = user
    }
  },
  
  actions: {
    async login({ commit }, credentials) {
      const user = await api.login(credentials)
      commit('SET_USER', user)
    }
  }
})

在组件中使用:

js 复制代码
import { useStore } from 'vuex'

export default {
  setup() {
    const store = useStore()
    
    // 获取状态
    const count = computed(() => store.state.count)
    const doubleCount = computed(() => store.getters.doubleCount)
    
    // 修改状态
    function increment() {
      store.commit('INCREMENT')
    }
    
    // 异步操作
    function login() {
      store.dispatch('login', { username: 'admin', password: '123' })
    }
    
    return { count, doubleCount, increment, login }
  }
}
Pinia(现代推荐)

与 Vuex 相比,Pinia 不仅提供了一个更简单的 API,也提供了符合组合式 API 风格的 API

特点:

  • 更简洁的API
  • 更好的TypeScript支持
  • 没有mutations,只有actions
  • 支持多个store

基本使用:

js 复制代码
// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  // 状态
  state: () => ({
    count: 0
  }),
  
  // 计算属性
  getters: {
    doubleCount: (state) => state.count * 2
  },
  
  // 方法(支持同步和异步)
  actions: {
    increment() {
      this.count++
    },
    
    async fetchCount() {
      const result = await api.getCount()
      this.count = result
    }
  }
})

组合式API风格的Store:

js 复制代码
// stores/counter.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCounterStore = defineStore('counter', () => {
  // 状态
  const count = ref(0)
  
  // 计算属性
  const doubleCount = computed(() => count.value * 2)
  
  // 方法
  function increment() {
    count.value++
  }
  
  return { count, doubleCount, increment }
})

在组件中使用:

js 复制代码
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'

export default {
  setup() {
    const store = useCounterStore()
    
    // 保持响应性的解构
    const { count, doubleCount } = storeToRefs(store)
    
    // 方法可以直接解构
    const { increment } = store
    
    return { count, doubleCount, increment }
  }
}
Pinia 高级特性

1. 持久化存储

js 复制代码
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    token: '',
    userInfo: null
  }),
  
  actions: {
    login(credentials) {
      // 登录逻辑
    }
  },
  
  // 持久化配置
  persist: {
    storage: localStorage,
    paths: ['token', 'userInfo']
  }
})

2. Store组合

js 复制代码
// stores/auth.js
export const useAuthStore = defineStore('auth', () => {
  const userStore = useUserStore() // 使用其他store
  
  function logout() {
    userStore.clearUser()
    // 其他登出逻辑
  }
  
  return { logout }
})
Vuex vs Pinia 对比
特性 Vuex Pinia
API复杂度 复杂(4个概念) 简单(3个概念)
TypeScript支持 一般 优秀
代码分割 需要modules 天然支持
开发体验 较复杂 更直观
文件大小 较大 更小

选择建议:

  • 新项目 → Pinia
  • Vue 3项目 → Pinia
  • 需要强TypeScript支持 → Pinia
  • 老项目维护 → 继续使用Vuex

12. 构建工具 Vite

什么是Vite?

简单理解: 超快的项目构建工具 ,就像高速列车

传统构建工具(Webpack):

  • 像普通火车,停很多站,速度慢
  • 需要打包所有文件才能启动

Vite:

  • 像高铁,直达目标,速度快
  • 按需加载,启动秒级
主要特性

1. 极速的开发服务器启动

perl 复制代码
# 创建Vite项目
npm create vue@latest my-project
cd my-project
npm install
npm run dev  # 秒级启动!

2. 闪电般的热更新(HMR)

  • 修改代码后,页面几乎瞬间更新
  • 保持应用状态,不会丢失数据

3. 原生ES模块支持

  • 开发时直接使用ES模块
  • 生产环境自动优化打包
项目结构
js 复制代码
my-vue-project/
├── public/              # 静态资源
├── src/
│   ├── assets/         # 源码资源
│   ├── components/     # 组件
│   ├── views/          # 页面
│   ├── router/         # 路由
│   ├── stores/         # 状态管理
│   ├── App.vue         # 根组件
│   └── main.js         # 入口文件
├── index.html          # HTML模板
├── vite.config.js      # Vite配置
└── package.json        # 项目配置
Vite配置
js 复制代码
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

export default defineConfig({
  plugins: [vue()],
  
  // 路径别名
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    }
  },
  
  // 开发服务器配置
  server: {
    port: 3000,
    open: true, // 自动打开浏览器
    cors: true  // 允许跨域
  },
  
  // 构建配置
  build: {
    outDir: 'dist',
    sourcemap: true
  }
})
环境变量

创建环境文件:

js 复制代码
# .env.development(开发环境)
VITE_API_URL=http://localhost:3000/api
VITE_APP_TITLE=我的应用(开发)

# .env.production(生产环境)
VITE_API_URL=https://api.example.com
VITE_APP_TITLE=我的应用

在代码中使用:

arduino 复制代码
// 只有以VITE_开头的变量才会暴露给客户端
console.log(import.meta.env.VITE_API_URL)
console.log(import.meta.env.VITE_APP_TITLE)

第四部分:实战应用

13. 项目结构设计

标准项目结构
js 复制代码
vue-project/
├── public/                    # 静态资源(不会被构建处理)
│   ├── favicon.ico
│   └── index.html
├── src/
│   ├── assets/               # 静态资源(会被构建处理)
│   │   ├── images/
│   │   ├── styles/
│   │   └── fonts/
│   ├── components/           # 公共组件
│   │   ├── common/          # 通用组件
│   │   └── ui/              # UI组件
│   ├── views/               # 页面组件
│   │   ├── Home/
│   │   ├── About/
│   │   └── User/
│   ├── router/              # 路由配置
│   │   └── index.js
│   ├── stores/              # 状态管理
│   │   ├── modules/
│   │   └── index.js
│   ├── composables/         # 组合函数
│   │   ├── useAuth.js
│   │   └── useApi.js
│   ├── utils/               # 工具函数
│   │   ├── request.js
│   │   └── helpers.js
│   ├── App.vue              # 根组件
│   └── main.js              # 入口文件
├── tests/                   # 测试文件
├── vite.config.js           # Vite配置
├── package.json
└── README.md
组件命名规范

文件命名:

  • 组件文件:PascalCase(大驼峰)
  • 例如:MyComponent.vueUserProfile.vue

组件使用:

xml 复制代码
<!-- 在模板中使用kebab-case -->
<user-profile />
<my-component />

<!-- 或者使用PascalCase -->
<UserProfile />
<MyComponent />
代码组织原则

1. 单一职责原则

js 复制代码
<!-- ❌ 不好的例子:一个组件做太多事 -->
<template>
  <div>
    <!-- 用户信息 -->
    <!-- 订单列表 -->
    <!-- 支付模块 -->
    <!-- 评论系统 -->
  </div>
</template>

<!-- ✅ 好的例子:拆分成多个组件 -->
<template>
  <div>
    <UserInfo />
    <OrderList />
    <PaymentModule />
    <CommentSystem />
  </div>
</template>

2. 组件层级

js 复制代码
页面组件(Views) 
└── 业务组件(Business Components)
    └── 基础组件(Base Components)
        └── UI组件(UI Components)
API接口管理
js 复制代码
// utils/request.js - 请求封装
import axios from 'axios'

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

// 请求拦截器
request.interceptors.request.use(config => {
  const token = localStorage.getItem('token')
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

// 响应拦截器
request.interceptors.response.use(
  response => response.data,
  error => {
    console.error('请求错误:', error)
    return Promise.reject(error)
  }
)

export default request
js 复制代码
// api/user.js - API接口
import request from '@/utils/request'

export const userApi = {
  // 获取用户信息
  getUserInfo(id) {
    return request.get(`/users/${id}`)
  },
  
  // 更新用户信息
  updateUser(id, data) {
    return request.put(`/users/${id}`, data)
  },
  
  // 用户登录
  login(credentials) {
    return request.post('/auth/login', credentials)
  }
}

14. 最佳实践

性能优化

1. 组件懒加载

js 复制代码
// 路由懒加载
const Home = () => import('@/views/Home.vue')
const About = () => import('@/views/About.vue')

// 组件懒加载
<script setup>
import { defineAsyncComponent } from 'vue'

const AsyncComponent = defineAsyncComponent(() => 
  import('@/components/HeavyComponent.vue')
)
</script>

2. v-memo 优化列表渲染

js 复制代码
<template>
  <div v-for="item in list" :key="item.id" v-memo="[item.id, item.selected]">
    <!-- 只有id或selected变化时才重新渲染 -->
    {{ item.name }}
  </div>
</template>

3. computed 代替复杂表达式

js 复制代码
<!-- ❌ 不好的做法 -->
<template>
  <div>{{ users.filter(u => u.active).map(u => u.name).join(', ') }}</div>
</template>

<!-- ✅ 好的做法 -->
<template>
  <div>{{ activeUserNames }}</div>
</template>

<script setup>
const activeUserNames = computed(() => 
  users.filter(u => u.active).map(u => u.name).join(', ')
)
</script>
代码规范

1. 组件Props定义

js 复制代码
// ✅ 好的Props定义
defineProps({
  title: {
    type: String,
    required: true
  },
  count: {
    type: Number,
    default: 0
  },
  options: {
    type: Array,
    default: () => []
  }
})

2. 事件命名

js 复制代码
<!-- ✅ 动词-名词格式 -->
<MyComponent 
  @submit-form="handleSubmit"
  @update-user="handleUserUpdate"
  @delete-item="handleDelete"
/>

3. 样式组织

css 复制代码
<style scoped>
/* 组件根元素 */
.my-component {
  padding: 20px;
}

/* 子元素 */
.my-component__header {
  margin-bottom: 16px;
}

.my-component__content {
  line-height: 1.6;
}

/* 修饰符 */
.my-component--large {
  padding: 40px;
}

.my-component--dark {
  background-color: #333;
  color: white;
}
</style>
错误处理

1. 全局错误处理

js 复制代码
// main.js
const app = createApp(App)

app.config.errorHandler = (error, instance, info) => {
  console.error('全局错误:', error)
  console.error('错误信息:', info)
  // 发送错误报告到监控系统
}

2. 异步错误处理

js 复制代码
// composables/useAsyncData.js
export function useAsyncData(asyncFunction) {
  const data = ref(null)
  const loading = ref(false)
  const error = ref(null)
  
  async function execute() {
    loading.value = true
    error.value = null
    
    try {
      data.value = await asyncFunction()
    } catch (err) {
      error.value = err
      console.error('异步操作失败:', err)
    } finally {
      loading.value = false
    }
  }
  
  return { data, loading, error, execute }
}
测试策略

1. 单元测试

javascript 复制代码
// tests/components/MyButton.test.js
import { mount } from '@vue/test-utils'
import MyButton from '@/components/MyButton.vue'

describe('MyButton', () => {
  test('renders correctly', () => {
    const wrapper = mount(MyButton, {
      props: { text: 'Click me' }
    })
    
    expect(wrapper.text()).toBe('Click me')
  })
  
  test('emits click event', async () => {
    const wrapper = mount(MyButton)
    
    await wrapper.trigger('click')
    
    expect(wrapper.emitted('click')).toBeTruthy()
  })
})

🎯 费曼测试题

第一层:概念理解

  1. 用一句话解释什么是Vue.js?
  2. 响应式系统解决了什么问题?
  3. 组件和HTML元素有什么区别?

第二层:原理解释

  1. 为什么Vue能自动更新界面?
  2. Props和Emit是如何工作的?
  3. Computed和Methods有什么区别?

第三层:实际应用

  1. 什么时候用Options API,什么时候用Composition API?
  2. 如何设计一个组件的API?
  3. 什么情况下需要状态管理?

第四层:问题解决

  1. 如果列表渲染性能很慢,怎么优化?
  2. 组件之间如何通信最合适?
  3. 如何组织大型项目的代码结构?

📝 总结:Vue.js的核心理念

记住这个公式:

复制代码
声明式 + 响应式 + 组件化 = Vue.js

核心思想:

  1. 关注状态,而非DOM操作
  2. 声明结果,而非描述过程
  3. 组合功能,而非继承复杂性

学习心态:

  • 先理解概念,再学习语法
  • 多写代码,少背文档
  • 遇到问题先思考原理
  • 从简单项目开始实践

记住: 如果你能用简单的话向别人解释Vue.js的概念,说明你真的理解了!


🎉 恭喜你完成了Vue.js全栈知识点的费曼学习法指南!现在开始动手实践吧!

相关推荐
小猪猪屁5 小时前
WebAssembly 从零到实战:前端性能革命完全指南
前端·vue.js·webassembly
EMT5 小时前
记一个Vue.extend的用法
前端·vue.js
布兰妮甜5 小时前
封装Element UI中el-table表格为可配置列公用组件
vue.js·ui·el-table·前端开发·element-ui
jason_yang5 小时前
vue3自定义渲染内容如何当参数传递
前端·javascript·vue.js
gitboyzcf6 小时前
基于Taro4最新版微信小程序、H5的多端开发简单模板
前端·vue.js·taro
williamdsy6 小时前
实战复盘:pnpm Monorepo 中的 Nuxt 依赖地狱——Unhead 升级引发的连锁血案
vue.js·pnpm
冲!!6 小时前
vue3存储/获取本地或会话存储,封装存储工具,结合pina使用存储
前端·javascript·vue.js
BUG创建者6 小时前
uniapp vue页面传参到webview.nvue页面的html或者另一vue中
vue.js·uni-app·html