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 setuprefreactivecomputedwatch
新内置组件 Fragment(多根节点)、TeleportSuspense
其他改变 新生命周期钩子、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 })

⚠️ 修改对象内部属性时,newValoldVal同一个对象

情况三:监视 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 将 beforeCreatecreated 合并到了 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 只转换数据,VuetoRefs 会转换所有内容(包括 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-enterv-enter-from
v-model 替代 v-bind.sync
v-if / v-for 优先级 v-if 优先级更高
移除 $on$off$once$childrenfilters

九、💡 思考与创意用法

🧠 核心设计思想

  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 / $oncemitt
  • VuexPinia
  • v-bind.syncv-model:xxx
  • 过滤器 {``{ msg | capitalize }} → 计算属性或方法
  • $childrenrefsprovide/inject
  • 事件总线 → mitt
  • v-enterv-enter-from

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


相关推荐
凉、介1 小时前
深入理解 ARMv8-A|Application Binary Interface (ABI)
c语言·笔记·学习·嵌入式·arm
lcj25111 小时前
【stack、queue、deque、priority_queue】C++ 栈 / 队列 / 优先级队列全解析!手撕实现 + 二叉树层序遍历(附源码)
开发语言·c++·笔记
zhangakirn1 小时前
Systems Biology Part 1学习笔记
笔记·学习
Cloud_Shy6182 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第四章 Item 25 - 26)
开发语言·人工智能·经验分享·笔记·python·学习方法
likerhood2 小时前
服务器下载 Hugging Face 模型笔记:以 Qwen2.5-Coder-7B-CL 为例
运维·服务器·笔记
是上好佳佳佳呀4 小时前
【数据分析|Day02】Matplotlib 数据可视化笔记
笔记·matplotlib
三品吉他手会点灯12 小时前
C语言学习笔记 - 44.运算符和表达式 - 运算符2 - 除法与取余运算符
c语言·开发语言·笔记·算法
2601_colin12 小时前
Codex插件全流程实战指南
开发语言·经验分享·笔记·微信开放平台
疯狂打码的少年13 小时前
输入输出控制方式:DMA(直接存储器存取)
网络·笔记