Vue3 快速上手 — 精华笔记

📖 目录

  • [一、Vue3 简介](#一、Vue3 简介)
  • [二、创建 Vue3 工程](#二、创建 Vue3 工程)
  • [三、Vue3 核心语法](#三、Vue3 核心语法)
  • [四、Vue Router 路由](#四、Vue Router 路由)
  • [五、Pinia 状态管理](#五、Pinia 状态管理)
  • 六、组件通信
  • [七、其他 API](#七、其他 API)
  • [八、Vue3 新组件](#八、Vue3 新组件)
  • [九、💡 思考与创意用法](#九、💡 思考与创意用法)

一、Vue3 简介

2020 年 9 月 18 日发布,代号 One Piece (海贼王)

经历:4800+ 次提交、40+ 个 RFC、600+ 次 PR、300+ 贡献者

1.1 性能提升

指标 提升幅度
打包体积 减少 41%
初次渲染 快 55%
更新渲染 快 133%
内存占用 减少 54%

1.2 源码升级

  • 使用 Proxy 代替 defineProperty 实现响应式
  • 重写虚拟 DOM 的实现和 Tree-Shaking

1.3 拥抱 TypeScript

Vue3 对 TypeScript 的支持更加完善,类型推导更准确。

1.4 新特性一览

类别 内容
Composition API setup、ref、reactive、computed、watch
新内置组件 Fragment(多根节点)、Teleport、Suspense
其他改变 新生命周期钩子、data 必须为函数、移除 keyCode 修饰符

💡 思考 :Vue3 的核心设计哲学是 "更好的逻辑复用" 和 "更细粒度的响应式"。Composition API 让相关逻辑聚合在一起,而非像 Options API 那样分散在 data/methods/computed 中。


二、创建 Vue3 工程

2.1 基于 vue-cli 创建(已进入维护模式)

bash 复制代码
vue --version          # 确保 @vue/cli >= 4.5.0
npm install -g @vue/cli
vue create vue_test    # 选择 3.x
cd vue_test && npm run serve

2.2 基于 Vite 创建(⭐ 推荐)

Vite 优势:轻量快速热重载、开箱即用支持 TS/JSX/CSS、真正的按需编译

bash 复制代码
npm create vue@latest

配置选项:

选项 说明
Project name 项目名称
Add TypeScript ✅ 推荐
Add Vue Router 按需
Add Pinia 按需
Add Vitest 按需
Add ESLint ✅ 推荐

2.3 关键变化

复制代码
Vite 项目中 index.html 是入口文件(在项目最外层)
Vue3 通过 createApp 函数创建应用实例
Vue3 模板中可以没有根标签(Fragment)

💡 创意用法 :利用 Vite 的 npm create vue@latest 快速搭建原型项目,配合 --template 参数可以自定义项目模板,团队协作时统一项目结构。


三、Vue3 核心语法

3.1 Options API vs Composition API

复制代码
┌─────────────────────────────────────────────────┐
│              Options API (Vue2)                    │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐         │
│  │   data   │ │ methods  │ │computed  │  ← 分散  │
│  └──────────┘ └──────────┘ └──────────┘         │
│  同一功能的代码散落在不同配置项中                    │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│           Composition API (Vue3)                  │
│  ┌─────────────────────────────────┐            │
│  │  功能A: data + methods + computed │  ← 聚合    │
│  ├─────────────────────────────────┤            │
│  │  功能B: data + methods + computed │  ← 聚合    │
│  └─────────────────────────────────┘            │
│  相关功能的代码组织在一起                           │
└─────────────────────────────────────────────────┘

3.2 setup --- Composition API 的舞台

核心特点:

特性 说明
返回对象 属性/方法可在模板中直接使用
this 访问 undefined(Vue3 不再依赖 this)
执行时机 在 beforeCreate 之前调用
setup 语法糖 <script setup lang="ts"> 简化写法

setup 语法糖 + 组件命名:

bash 复制代码
npm i vite-plugin-vue-setup-extend -D
ts 复制代码
// vite.config.ts
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
export default defineConfig({
  plugins: [VueSetupExtend()]
})
vue 复制代码
<script setup lang="ts" name="Person">
// 直接编写逻辑,无需 return
</script>

3.3 ref --- 创建基本类型响应式数据

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

let name = ref('张三')   // RefImpl 实例对象
let age = ref(18)

// JS 中操作需要 .value
name.value = '李四'
age.value += 1

// 模板中直接使用,无需 .value
// {{ name }}、{{ age }}

⚠️ 注意 :name 本身不是响应式的,name.value 才是响应式的。

3.4 reactive --- 创建对象类型响应式数据

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

let car = reactive({ brand: '奔驰', price: 100 })
let games = reactive([
  { id: '01', name: '英雄联盟' },
  { id: '02', name: '王者荣耀' }
])

// 深层次响应式 ------ 嵌套属性也是响应式的
car.price += 10
games[0].name = '流星蝴蝶剑'

3.5 ref 也能处理对象类型

ts 复制代码
let car = ref({ brand: '奔驰', price: 100 })

// 内部实际调用了 reactive
car.value.price += 10  // 注意需要 .value

3.6 🔑 ref vs reactive 对比

维度 ref reactive
适用类型 基本类型 + 对象类型 仅对象类型
操作方式 需要 .value 直接访问
重新赋值 ✅ 可以(xxx.value = newObj) ❌ 失去响应式(需用 Object.assign)
深层响应 对象类型自动深层 自动深层

使用原则:

复制代码
📌 基本类型 → 必须用 ref
📌 对象类型、层级不深 → ref / reactive 均可
📌 对象类型、层级较深 → 推荐 reactive

3.7 toRefs 与 toRef

ts 复制代码
import { reactive, toRefs, toRef } from 'vue'

let person = reactive({ name: '张三', age: 18, gender: '男' })

// 批量转换:保持响应式能力
let { name, gender } = toRefs(person)

// 单个转换
let age = toRef(person, 'age')

// 使用时仍需 .value
name.value += '~'
age.value += 1

💡 思考 :toRefs 在解构 reactive 对象时特别有用,避免解构后丢失响应式。这是 Vue3 中 "保持响应式引用链" 的关键手段。

3.8 computed --- 计算属性

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

let firstName = ref('zhang')
let lastName = ref('san')

// 只读计算属性
let fullName = computed(() => firstName.value + '-' + lastName.value)

// 可读可写计算属性
let fullName = computed({
  get() { return firstName.value + '-' + lastName.value },
  set(val) {
    firstName.value = val.split('-')[0]
    lastName.value = val.split('-')[1]
  }
})

3.9 watch --- 侦听器(五种情况)

情况一:监视 ref 定义的基本类型
ts 复制代码
let sum = ref(0)
watch(sum, (newVal, oldVal) => {
  console.log('sum 变化了', newVal, oldVal)
  if (newVal >= 10) stopWatch()  // 停止监视
})
情况二:监视 ref 定义的对象类型
ts 复制代码
let person = ref({ name: '张三', age: 18 })

// 默认监视地址值,需手动开启深度监视
watch(person, (newVal, oldVal) => {
  console.log('person 变化了', newVal, oldVal)
}, { deep: true })

⚠️ 修改对象内部属性时,newVal 和 oldVal 是同一个对象。

情况三:监视 reactive 定义的对象类型
ts 复制代码
let person = reactive({ name: '张三', age: 18 })

// 默认开启深度监视
watch(person, (newVal, oldVal) => {
  console.log('person 变化了', newVal, oldVal)
})
情况四:监视对象中的某个属性
ts 复制代码
let person = reactive({ name: '张三', age: 18, car: { c1: '奔驰', c2: '宝马' } })

// 基本类型属性 → 必须写成函数
watch(() => person.name, (newVal, oldVal) => { /* ... */ })

// 对象类型属性 → 推荐写成函数 + deep
watch(() => person.car, (newVal, oldVal) => { /* ... */ }, { deep: true })
情况五:监视多个数据
ts 复制代码
watch([() => person.name, person.car], (newVal, oldVal) => {
  console.log('多个数据变化了', newVal, oldVal)
}, { deep: true })

3.10 watchEffect --- 自动依赖收集

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

let temp = ref(0)
let height = ref(0)

// 自动追踪函数内使用的响应式数据
const stop = watchEffect(() => {
  if (temp.value >= 50 || height.value >= 20) {
    console.log('联系服务器')
  }
})

watch vs watchEffect:

维度 watch watchEffect
指定数据 ✅ 明确指定 ❌ 自动收集
获取旧值 ✅ 可以 ❌ 不可以
时机 惰性执行 立即执行

3.11 标签的 ref 属性

ts 复制代码
// 用在普通 DOM 上 → 获取 DOM 节点
let title1 = ref()
// <h1 ref="title1">标题</h1>
console.log(title1.value)  // <h1>元素</h1>

// 用在组件上 → 获取组件实例(需 defineExpose)
let ren = ref()
// <Person ref="ren" />
console.log(ren.value.name)  // 子组件需 defineExpose({ name })

3.12 props(TypeScript 版)

ts 复制代码
// 定义类型
export interface PersonInter {
  id: string
  name: string
  age: number
}
export type Persons = Array<PersonInter>

// 子组件接收 props(三种写法)
// 1. 仅接收
const props = defineProps(['list'])
// 2. 接收 + 限制类型
defineProps<{ list: Persons }>()
// 3. 接收 + 限制类型 + 默认值 + 必要性
let props = withDefaults(defineProps<{ list?: Persons }>(), {
  list: () => [{ id: '01', name: '默认', age: 18 }]
})

3.13 生命周期

复制代码
Vue2                          Vue3
─────────────────────────────────────────
beforeCreate        →         setup()
created             →         setup()
beforeMount         →         onBeforeMount()
mounted             →         onMounted()          ⭐ 常用
beforeUpdate        →         onBeforeUpdate()
updated             →         onUpdated()          ⭐ 常用
beforeDestroy       →         onBeforeUnmount()    ⭐ 常用
destroyed           →         onUnmounted()

💡 思考 :Vue3 将 beforeCreate 和 created 合并到了 setup 中,因为 setup 本身就在这两个钩子之间执行。这减少了钩子数量,让初始化逻辑更集中。

3.14 自定义 Hook

本质:把 setup 中的 Composition API 封装成可复用的函数,类似 Vue2 的 mixin

ts 复制代码
// hooks/useSum.ts
import { ref, onMounted } from 'vue'

export default function () {
  let sum = ref(0)
  const increment = () => { sum.value += 1 }
  const decrement = () => { sum.value -= 1 }
  onMounted(() => { increment() })
  return { sum, increment, decrement }
}
vue 复制代码
<!-- 组件中使用 -->
<script setup lang="ts">
import useSum from './hooks/useSum'
import useDog from './hooks/useDog'

let { sum, increment, decrement } = useSum()
let { dogList, getDog } = useDog()
</script>

💡 创意用法:

  • useLocalStorage --- 响应式 localStorage 封装
  • useMousePosition --- 实时追踪鼠标坐标
  • useDebounce --- 防抖值封装
  • useFetch --- 带加载状态的请求封装
  • useDarkMode --- 暗黑模式切换

四、Vue Router 路由

4.1 基本配置

ts 复制代码
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/pages/Home.vue'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/home', component: Home },
    { path: '/about', component: About }
  ]
})
export default router
ts 复制代码
// main.ts
import router from './router/index'
app.use(router)

4.2 路由器工作模式

模式 API 优点 缺点
History createWebHistory() URL 美观(无 #) 需服务端配合,刷新可能 404
Hash createWebHashHistory() 兼容性好,无需服务端配置 URL 带 #,SEO 不友好

4.3 嵌套路由

ts 复制代码
{
  name: 'xinwen',
  path: '/news',
  component: News,
  children: [
    { name: 'xiang', path: 'detail', component: Detail }
  ]
}

4.4 路由传参

query 参数
vue 复制代码
<!-- 传递 -->
<RouterLink :to="{
  path: '/news/detail',
  query: { id: news.id, title: news.title }
}">{{ news.title }}</RouterLink>

<!-- 接收 -->
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.query.id, route.query.title)
</script>
params 参数
vue 复制代码
<!-- 传递(对象写法必须用 name) -->
<RouterLink :to="{
  name: 'xiang',
  params: { id: news.id, title: news.title }
}">{{ news.title }}</RouterLink>

<!-- 接收 -->
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params.id, route.params.title)
</script>

⚠️ 使用 params 时需提前在路由规则中占位:path: 'detail/:id/:title'

4.5 路由 props 配置

ts 复制代码
{
  name: 'xiang',
  path: 'detail/:id/:title',
  component: Detail,
  // 三种写法:
  props: { a: 1, b: 2 },          // 对象写法:静态 props
  // props: true,                   // 布尔写法:params → props
  props(route) { return route.query } // 函数写法:query → props
}

4.6 编程式导航

ts 复制代码
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()   // 路由信息(替代 $route)
const router = useRouter()  // 路由器(替代 $router)

router.push('/home')       // 追加历史记录
router.replace('/about')   // 替换当前记录

4.7 其他要点

功能 说明
命名路由 name: 'zhuye',跳转时用 { name: 'zhuye' }
replace 属性 <RouterLink replace> 替换而非追加历史记录
重定向 { path: '/', redirect: '/about' }

💡 思考 :路由的 props: true 配置是 "解耦路由参数与组件" 的最佳实践,让组件可以通过 props 接收参数,而非直接依赖 useRoute(),提高了组件的可复用性和可测试性。


五、Pinia 状态管理

Vue3 官方推荐的状态管理库,替代 Vuex

5.1 搭建环境

bash 复制代码
npm install pinia
ts 复制代码
// main.ts
import { createPinia } from 'pinia'
const pinia = createPinia()
app.use(pinia)

5.2 核心概念

复制代码
Pinia Store 三要素:
┌────────────────────────────────────────┐
│  State    ≈  data      (状态)        │
│  Getters  ≈  computed  (计算)        │
│  Actions  ≈  methods   (动作)        │
└────────────────────────────────────────┘

5.3 定义 Store(选项式写法)

ts 复制代码
// store/count.ts
import { defineStore } from 'pinia'

export const useCountStore = defineStore('count', {
  state() {
    return { sum: 6, school: 'jdfs' }
  },
  actions: {
    increment(value: number) {
      if (this.sum < 10) this.sum += value
    },
    decrement(value: number) {
      if (this.sum > 1) this.sum -= value
    }
  },
  getters: {
    bigSum: (state): number => state.sum * 10,
    upperSchool(): string {
      return this.school.toUpperCase()
    }
  }
})

5.4 修改数据(三种方式)

ts 复制代码
const countStore = useCountStore()

// 方式一:直接修改
countStore.sum = 666

// 方式二:批量修改
countStore.$patch({ sum: 999, school: 'jdfs' })

// 方式三:通过 action 修改(可包含业务逻辑)
countStore.increment(5)

5.5 storeToRefs

ts 复制代码
import { storeToRefs } from 'pinia'

const countStore = useCountStore()
const { sum, school, bigSum } = storeToRefs(countStore)
const { increment, decrement } = countStore  // actions 不需要 storeToRefs

⚠️ 重要 :storeToRefs 只转换数据,Vue 的 toRefs 会转换所有内容(包括 actions)。

5.6 $subscribe --- 侦听 state 变化

ts 复制代码
talkStore.$subscribe((mutate, state) => {
  console.log('talkList 变化了', mutate, state)
  localStorage.setItem('talkList', JSON.stringify(state))
})

5.7 组合式写法

ts 复制代码
import { defineStore } from 'pinia'
import { reactive } from 'vue'
import axios from 'axios'
import { nanoid } from 'nanoid'

export const useTalkStore = defineStore('talk', () => {
  // state
  const talkList = reactive(
    JSON.parse(localStorage.getItem('talkList') as string) || []
  )

  // action
  async function getATalk() {
    let { data: { content: title } } = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
    let obj = { id: nanoid(), title }
    talkList.unshift(obj)
  }

  return { talkList, getATalk }
})

💡 创意用法:

  • 持久化 Store :配合 $subscribe + localStorage 实现数据持久化
  • Store 插件:编写 Pinia 插件实现全局错误处理、日志记录
  • SSR 支持:Pinia 天然支持 SSR,可在服务端渲染时安全使用

六、组件通信

Vue3 组件通信方式全景图:

复制代码
                    ┌──────────────┐
                    │   父 ↔ 子    │
                    │   props      │
                    │   自定义事件  │
                    │   v-model    │
                    └──────┬───────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
     ┌────────┴───┐ ┌────┴────┐ ┌────┴────────┐
     │  父 → 子    │ │ 子 → 父 │ │ 任意组件    │
     │  $refs      │ │ $parent │ │  mitt       │
     └────────────┘ └─────────┘ │  pinia      │
     ┌────────────┐ ┌──────────┐ └─────────────┘
     │  祖 → 孙   │ │ 祖 → 孙  │
     │  $attrs    │ │ provide  │
     │            │ │ inject   │
     └────────────┘ └──────────┘
     ┌────────────────────────────┐
     │  父 → 子(内容分发)       │
     │  slot(插槽)              │
     └────────────────────────────┘

6.1 props

vue 复制代码
<!-- 父组件 -->
<Child :car="car" :getToy="getToy" />

<!-- 子组件 -->
<script setup>
defineProps(['car', 'getToy'])
</script>

6.2 自定义事件

vue 复制代码
<!-- 父组件:绑定自定义事件 -->
<Child @send-toy="toy = $event" />

<!-- 子组件:触发事件 -->
<script setup>
const emit = defineEmits(['send-toy'])
emit('send-toy', '奥特曼')
</script>

6.3 mitt --- 事件总线

ts 复制代码
// utils/emitter.ts
import mitt from 'mitt'
const emitter = mitt()
export default emitter
ts 复制代码
// 接收方
import emitter from '@/utils/emitter'
import { onUnmounted } from 'vue'

emitter.on('send-toy', (value) => { console.log(value) })
onUnmounted(() => { emitter.off('send-toy') })

// 发送方
import emitter from '@/utils/emitter'
emitter.emit('send-toy', toy.value)

6.4 v-model 组件通信

vue 复制代码
<!-- 父组件 -->
<MyInput v-model="userName" />
<!-- 等价于 -->
<MyInput :modelValue="userName" @update:model-value="userName = $event" />

<!-- 子组件 -->
<script setup>
defineProps(['modelValue'])
const emit = defineEmits(['update:model-value'])
</script>
<template>
  <input :value="modelValue" @input="emit('update:model-value', $event.target.value)">
</template>

💡 创意用法 :可以自定义 v-model 的参数名实现多个双向绑定:

<MyInput v-model:username="name" v-model:password="pwd" />

6.5 $attrs --- 祖→孙透传

vue 复制代码
<!-- 子组件:透传所有 attrs -->
<GrandChild v-bind="$attrs" />

$attrs 自动排除 props 中已声明的属性,只传递"未消费"的属性。

6.6 refs 与 parent

API 方向 用途
$refs 父→子 获取子组件实例或 DOM
$parent 子→父 获取父组件实例

6.7 provide / inject --- 祖孙通信

ts 复制代码
// 祖先组件
provide('moneyContext', { money, updateMoney })
provide('car', car)

// 后代组件
let { money, updateMoney } = inject('moneyContext', { money: 0, updateMoney: () => {} })
let car = inject('car')

💡 思考 :provide/inject 是 Vue3 中实现 "依赖注入" 的核心机制,特别适合主题、国际化、权限等跨层级共享的场景。

6.8 slot --- 插槽

vue 复制代码
<!-- 默认插槽 -->
<Category title="游戏">
  <ul><li v-for="g in games">{{ g.name }}</li></ul>
</Category>

<!-- 具名插槽 -->
<Category>
  <template v-slot:s1>内容1</template>
  <template #s2>内容2</template>  <!-- # 是 v-slot: 的缩写 -->
</Category>

<!-- 作用域插槽:子组件向父组件暴露数据 -->
<Game v-slot="params">
  <ul><li v-for="g in params.games">{{ g.name }}</li></ul>
</Game>

💡 创意用法 :作用域插槽是 Vue 中 "控制反转" 的经典实现。子组件负责数据,父组件负责渲染结构,实现了数据与视图的解耦。可以用来构建高度可定制的表格、列表等组件。


七、其他 API

7.1 shallowRef 与 shallowReactive

ts 复制代码
// 只跟踪顶层,不关心内部属性变化
let myVar = shallowRef(initialValue)
let myObj = shallowReactive({ ... })

🎯 适用场景 :大型对象/列表,只需监听整体替换,不需要深层响应。性能优化利器。

7.2 readonly 与 shallowReadonly

ts 复制代码
const readOnlyCopy = readonly(original)          // 深只读
const shallowCopy = shallowReadonly(original)     // 浅只读(顶层只读)

🎯 适用场景:保护全局状态/配置不被意外修改。

7.3 toRaw 与 markRaw

ts 复制代码
let rawPerson = toRaw(person)   // 获取原始对象(非响应式)

let citys = markRaw([...])     // 标记对象永不转为响应式
let citys2 = reactive(citys)   // 创建失败!

🎯 适用场景:

  • toRaw:将响应式对象传给非 Vue 库时使用
  • markRaw:防止 Mock.js 数据被转为响应式(避免性能浪费)

7.4 customRef --- 自定义 ref

ts 复制代码
import { customRef } from 'vue'

export default function (initValue: string, delay: number) {
  let msg = customRef((track, trigger) => {
    let timer: number
    return {
      get() {
        track()     // 告诉 Vue 追踪这个数据
        return initValue
      },
      set(value) {
        clearTimeout(timer)
        timer = setTimeout(() => {
          initValue = value
          trigger()  // 通知 Vue 数据变化了
        }, delay)
      }
    }
  })
  return { msg }
}

💡 创意用法 :customRef 可以实现防抖输入、节流输入、带验证的输入等高级功能。


八、Vue3 新组件

8.1 Teleport --- 传送门

vue 复制代码
<teleport to='body'>
  <div class="modal" v-show="isShow">
    <h2>弹窗</h2>
    <button @click="isShow = false">关闭</button>
  </div>
</teleport>

💡 思考 :Teleport 解决了 "组件逻辑属于当前组件,但 DOM 结构需要在 body 下" 的矛盾,如模态框、通知、Tooltip 等。

8.2 Suspense --- 异步组件加载

vue 复制代码
<Suspense>
  <template #default>
    <AsyncChild />
  </template>
  <template #fallback>
    <h3>加载中......</h3>
  </template>
</Suspense>
ts 复制代码
import { defineAsyncComponent } from 'vue'
const Child = defineAsyncComponent(() => import('./Child.vue'))

8.3 全局 API 转移到应用对象

复制代码
Vue2                          Vue3
─────────────────────────────────────
Vue.component()        →     app.component()
Vue.directive()        →     app.directive()
Vue.use()              →     app.use()
Vue.mixin()            →     app.mixin()
new Vue()              →     createApp()

8.4 其他破坏性变更

变更 说明
过渡类名 v-enter → v-enter-from
v-model 替代 v-bind.sync
v-if / v-for 优先级 v-if 优先级更高
移除 $on、$off、$once、$children、filters

九、💡 思考与创意用法

🧠 核心设计思想

  1. 组合优于继承:Composition API 通过函数组合实现逻辑复用,比 Mixin 更清晰
  2. 响应式是核心:Proxy 带来的深层响应式,让数据驱动视图更加自然
  3. 渐进式增强:Vue3 完全兼容 Vue2,可以逐步迁移

🚀 实战创意用法

1. 自定义 Hook 库
复制代码
useDarkMode      --- 暗黑模式,自动读取系统偏好
useLocalStorage  --- 响应式 localStorage
useMouse         --- 实时鼠标位置追踪
useDebounce      --- 防抖值
useFetch         --- 带加载/错误状态的请求封装
useIntersection  --- 元素可见性检测(懒加载)
useClipboard     --- 剪贴板读写
useWebSocket     --- WebSocket 连接管理
2. Pinia 持久化插件
ts 复制代码
// 利用 $subscribe + localStorage 实现数据持久化
// 也可以使用 pinia-plugin-persistedstate 插件
store.$subscribe((_, state) => {
  localStorage.setItem(store.$id, JSON.stringify(state))
})
3. 组件设计模式
模式 说明 示例
无渲染组件 只提供逻辑,通过插槽渲染 <RenderlessForm>
受控组件 v-model 双向绑定 <CustomInput v-model="value">
提供/注入 跨层级状态共享 主题系统、权限控制
作用域插槽 数据与视图解耦 可定制表格、列表
4. 性能优化技巧
复制代码
✅ 大型列表 → shallowRef / shallowReactive(避免深层响应开销)
✅ 只读数据 → readonly(防止意外修改 + 性能提示)
✅ 第三方对象 → markRaw(避免不必要的响应式转换)
✅ 防抖输入 → customRef(减少频繁更新)
✅ 异步组件 → defineAsyncComponent + Suspense(按需加载)
✅ 路由懒加载 → () => import('xxx.vue')(减小首屏包体积)
5. TypeScript 最佳实践
ts 复制代码
// 1. 为 props 定义接口
interface Props {
  title: string
  count?: number
  items: Array<{ id: string; name: string }>
}

// 2. 为 emit 定义类型
const emit = defineEmits<{
  change: [value: string]
  update: [id: string, data: object]
}>()

// 3. 为 store 定义类型
interface UserState {
  name: string
  age: number
}
export const useUserStore = defineStore('user', () => {
  const user = ref<UserState>({ name: '', age: 0 })
  return { user }
})

📋 Vue2 → Vue3 迁移清单

  • new Vue() → createApp()
  • data 选项改为函数
  • $on / $off / $once → mitt
  • Vuex → Pinia
  • v-bind.sync → v-model:xxx
  • 过滤器 {``{ msg | capitalize }} → 计算属性或方法
  • $children → refs 或 provide/inject
  • 事件总线 → mitt
  • v-enter → v-enter-from

📝 总结 :Vue3 的核心升级在于 Composition API 带来的逻辑组织革命、Proxy 带来的响应式性能飞跃、以及 Pinia 带来的更简洁的状态管理。掌握这些核心概念,配合 TypeScript 和自定义 Hook,可以构建出高质量、可维护的 Vue3 应用。


相关推荐
蒸蒸yyyyzwd8 小时前
AI应用相关可能的面试问题
笔记
叼烟扛炮9 小时前
[Git 实战] 学习笔记:从生成 SSH 密钥到解决 TortoiseGit 推送报错全指南
linux·运维·笔记·git·学习
蒸蒸yyyyzwd9 小时前
学习笔记 八股手撕
笔记·学习
揣一尾游鱼yu10 小时前
Spring上(IOC)笔记
java·笔记·spring·ioc
小李不想当小白12 小时前
BKP备份寄存器与RTC实时时钟(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
瑞码空间14 小时前
JSP与Servlet核心开发与CRUD实战笔记
java·笔记·servlet·jsp
La Pulga15 小时前
【FreeRTOS源码学习笔记】链表的实现
数据结构·笔记·stm32·mcu·链表·嵌入式·freertos
wuyoutrans17 小时前
以色列专利OA答复翻译,重点要避开哪些坑?
笔记
宝绿特塑业再生科技17 小时前
HDPE再生颗粒户外家具表面粉化机理与改性技术全解析
笔记·户外家具·再生塑料·塑木桌椅
凉、介18 小时前
深入理解 ARMv7-A | Generic Timer
笔记·学习·嵌入式·arm