普通视图

发现新文章,点击刷新页面。
昨天 — 2025年10月24日首页

为啥升Vue3 有啥优势?

作者 前端大付
2025年10月24日 11:00

Vue2 Vue3 对比

Vue3 通过 Proxy 响应式、Composition API、完整 TS 能力、编译器优化新内置能力(Teleport/Suspense/Fragments) ,系统性解决了 Vue2 在大型项目可维护性、类型安全、性能与可复用性上的天花板问题。

开发者需关注的特性

RFC 机制

简单说:ref 就是让一个值变成「响应式引用」。

import { ref } from 'vue'

const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

  • ref(0) 创建了一个响应式对象,结构为 { value: 0 }

  • 在模板中,会自动“解包”,不用 .value

<template>
  <div>{{ count }}</div> <!-- 会自动取 count.value -->
  <button @click="count++">+1</button>
</template>

常见使用场景

定义基础状态
const title = ref('Hello Vue3')
const visible = ref(false)
DOM 引用(替代 Vue2 的 $refs
<template>
  <input ref="inputRef" />
</template>

<script setup>
import { ref, onMounted } from 'vue'
const inputRef = ref(null)

onMounted(() => {
  inputRef.value.focus()
})
</script>
组合逻辑(Composables)
// useCounter.js
import { ref } from 'vue'
export function useCounter() {
  const count = ref(0)
  const inc = () => count.value++
  const dec = () => count.value--
  return { count, inc, dec }
}
// 组件中使用
const { count, inc, dec } = useCounter()

ref 的高级技巧

✅ 1. 与对象绑定
const person = ref({ name: 'Tom', age: 18 })
person.value.age++ // 响应式更新
✅ 2. 响应式计算
import { ref, computed } from 'vue'
const count = ref(2)
const double = computed(() => count.value * 2)
✅ 3. 监听 ref
import { watch } from 'vue'
watch(count, (newVal, oldVal) => {
  console.log('变化:', oldVal, '→', newVal)
})

核心原理简述

Vue3 内部定义大致如下(简化):

function ref(value) {
  return reactive({ value })
}
  • Vue 自动通过 Proxy 监听 .value
  • 模板中自动 .value 解包;
  • 保持了原始值响应式 + 对象响应式统一接口。

响应式系统

Vue2 在初始化数据时,会通过 Object.defineProperty 把每个属性“拦截”成带 getter/setter 的形式。

组件初始化 → 遍历 data → defineProperty 劫持每个 key
           → getter 收集 watcher
           → setter 触发 watcher.update()

function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    get() {
      console.log('get', key)
      return val
    },
    set(newVal) {
      console.log('set', key, newVal)
      val = newVal
    }
  })
}

const data = {}
defineReactive(data, 'count', 0)
data.count // get count
data.count = 1 // set count 1

Vue3 改用 Proxy,一层代理整个对象,无需遍历所有属性。

组件初始化 → reactive 创建 Proxy
           → getter(track) 收集依赖
           → setter(trigger) 触发副作用

const data = { count: 0 }
const p = new Proxy(data, {
  get(target, key, receiver) {
    console.log('get', key)
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    console.log('set', key, value)
    const res = Reflect.set(target, key, value, receiver)
    // 触发依赖更新
    return res
  }
})
p.count++ // get + set

Typescript 支持

Vue3 更加方便 早期发现问题成本会降低很多

Vue2(Class/装饰器)

import { Vue, Component, Prop } from 'vue-property-decorator'

@Component
export default class UserCard extends Vue {
  @Prop({ type: String, required: true }) readonly name!: string
  count = 0
  mounted() { /* this.name 类型常OK,但混用mixin易错 */ }
}

Vue3(<script setup> 推荐)

<script setup lang="ts">
const props = defineProps<{ name: string }>()
const emit = defineEmits<{
  (e: 'update:count', v: number): void
}>()

import { ref } from 'vue'
const count = ref(0)
function inc() { count.value++; emit('update:count', count.value) }
</script>

Options API VS Composition API / <script setup>

Vue2(Options API)分开写一块一块的功能

<!-- UserCard.vue -->
<template>
  <div>
    <h3>{{ title }}</h3>
    <p>{{ fullName }}</p>
    <input v-model="keyword" @keyup.enter="search" />
    <button @click="inc">{{ count }}</button>
  </div>
</template>

<script>
export default {
  props: { first: String, last: String },
  data() {
    return { title: 'User', count: 0, keyword: '' }
  },
  computed: {
    fullName() { return `${this.first} ${this.last}` }
  },
  watch: {
    keyword(nv) { console.log('kw:', nv) }
  },
  methods: {
    inc() { this.count++ },
    search() { this.$emit('search', this.keyword) }
  },
  created() { console.log('created') },
  mounted() { console.log('mounted') }
}
</script>

但 Options API 的写法也有几个很严重的问题: 由于所有数据都挂载在 this 之上,因而 Options API 的写法对 TypeScript 的类型推导很不友好,并且这样也不好做 Tree-shaking 清理代码。

新增功能基本都得修改 data、method 等配置,并且代码上 300 行之后,会经常上下反复横跳,开发很痛苦。

代码不好复用,Vue 2 的组件很难抽离通用逻辑,只能使用 mixin,还会带来命名冲突的问题。

Vue3(Composition API,<script setup> 推荐)

<!-- UserCard.vue -->
<template>
  <div>
    <h3>{{ title }}</h3>
    <p>{{ fullName }}</p>
    <input v-model="keyword" @keyup.enter="search" />
    <button @click="inc">{{ count }}</button>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted, onBeforeMount } from 'vue'

const props = defineProps<{ first: string; last: string }>()
const emit = defineEmits<{ (e: 'search', kw: string): void }>()

const title = ref('User')
const count = ref(0)
const keyword = ref('')

const fullName = computed(() => `${props.first} ${props.last}`)

watch(keyword, (nv) => console.log('kw:', nv))

function inc() { count.value++ }
function search() { emit('search', keyword.value) }

onBeforeMount(() => console.log('created'))
onMounted(() => console.log('mounted'))
</script>

用到的功能都 import 进来,对 Tree-shaking 很友好,我的例子里没用到功能,打包的时候会被清理掉 ,减小包的大小。

不再上下反复横跳,我们可以把一个功能模块的 methods、data 都放在一起书写,维护更轻松。

代码方便复用,可以把一个功能所有的 methods、data 封装在一个独立的函数里,复用代码非常容易。

Composotion API 新增的 return 等语句,在实际项目中使用

新一代工程化工具 Vite

Webpack 是“打包优先” —— 一切先打包再运行;
Vite 是“原生模块优先” —— 借助浏览器原生 ES Module 实现“按需加载”,再用 Rollup 打包生产。

并非是 Vue3 专属,Vite 主要提升的是开发的体验,Webpack 等工程化工具的原理,就是根据你的 import 依赖逻辑,形成一个依赖图,然后调用对应的处理工具,把整个项目打包后,放在内存里再启动调试。

由于要预打包,所以复杂项目的开发,启动调试环境需要 3 分钟都很常见,Vite 就是为了解决这个时间资源的消耗问题出现的。

  • Webpack(bundle-first)启动流程
  [开发者运行 dev][读取配置/插件/Loader][构建完整依赖图][打完整包(或多入口Chunk)][启动 DevServer,提供内存中的 bundle][浏览器加载单/多 bundle][HMR:文件变更][增量重新构建相关 chunk][推送热更新补丁 → 替换模块/触发刷新]

  • Vite(esm-first)启动流程

[开发者运行 dev][秒启本地 Dev Server][依赖预构建(一次性,用 esbuild)][按请求即时编译源码(如 .vue/.ts)][浏览器通过 ESM 逐模块请求][HMR:文件变更][仅编译受影响模块][精准替换该模块(ESM 热替换,无需重打包)]

解决了哪些问题(重要几点)

  1. 响应式缺陷(Vue2 的 getter/setter)
  • 痛点:数组下标/length 变更、对象新增/删除属性不响应,需 Vue.set/delete;深层依赖追踪易漏报。
  • Vue3:基于 Proxy 的响应式系统,天然支持属性新增/删除、数组操作,无需 set/delete,依赖追踪更准确,副作用更可控。
  1. 大型组件与逻辑复用困难(Options + mixins 冲突/命名污染)
  • 痛点:mixin 命名碰撞、来源不清;复杂组件 methods/computed/data 四散,难以围绕“功能”聚合。
  • Vue3:Composition APIsetup/ref/reactive/computed/watch)按“功能切片”组织代码,自定义 hooks(composables) 可复用且可测试、可类型推断,彻底替代大多数 mixins 场景。
  1. 类型与可维护性(TS 体验差)
  • 痛点:Vue2 TS 需要装饰器/额外语法,推断不稳;事件/props 的类型约束不友好。
  • Vue3:内置 TypeScript 一等公民defineComponent/emits/defineProps 等让 props/emit 有完善的类型检查与 IDE 推断。
  1. 性能与包体(编译/运行双端优化不足)
  • 痛点:VNode diff 粗粒度、静态节点重复计算,包不易摇树优化。
  • Vue3:编译器引入 patchFlag/静态提升/事件缓存 等;运行时 更快的 VDOM更好的 Tree-Shaking(按需打包核心模块),同等功能体积更小
  1. 生态与未来
  • 痛点:Vue2 生态逐渐维护最小化,新库偏向 Vue3。
  • Vue3:新生态(如 Naive UI、VueUse、Volar)全面围绕 Vue3/TS 优化,长期演进保障。
昨天以前首页
❌
❌