Vue3 核心变化一览

Vue3 版本重构核心基于两大核心考量,解决 Vue2 长期存在的架构短板、适配前端技术发展:

  • 技术迭代适配:依托 ES6+ 全新语言特性,弥补 ES5 语法的能力局限;
  • 修复架构缺陷:解决 Vue2 响应式局限、代码复用弱、大型项目可维护性差、TS 支持不完善等历史问题。

Vue2 已于 2023 年 12 月 31 日停止官方维护,Vue3 是目前唯一官方主推、持续迭代的稳定版本。

核心优势与新特性

  • 性能更强:重写虚拟 DOM、优化模板编译、静态节点标记、事件缓存,更新性能提升 1.3~2 倍,SSR 渲染速度提升 2~3 倍;
  • 体积更小:全面支持 Tree-Shaking,按需打包,剔除未使用 API,大幅减小生产包体积;
  • 维护性更高:组合式 API 实现逻辑集中管理,完美适配大型项目,TS 原生支持更友好;
  • 能力更全面:暴露底层响应式 API,贴近原生 DOM,支持自定义渲染器,拓展性极强。
  • 组合式 API(Composition API):替代分散的选项式 API,实现逻辑聚合、高效复用;
  • <script setup> 语法糖:组合式 API 简化写法,无需 return、自动解析顶层变量;
  • Fragments 多根节点:模板支持多个根标签,无需多余外层包裹节点;
  • Teleport 瞬移组件:将组件 DOM 挂载到 app 外任意节点(常用于弹窗、遮罩层);
  • Emits 事件声明:显式声明组件自定义事件,规范事件传递,替代 Vue2 隐式事件;
  • SFC 状态驱动 CSS:style 中可通过 v-bind 绑定组件变量,实现动态样式;
  • 增强 scoped 样式:支持 scoped 样式内写全局样式、插槽专属样式;
  • Suspense(实验性):优雅处理异步组件加载状态,配置 loading 兜底展示;
  • 自定义渲染器 createRenderer:脱离浏览器 DOM,适配小程序、桌面端等多端渲染。

Vue3 框架级官方推荐变更

Vue3 生态全面迭代,官方更新全套工程化工具链方案:

  • 构建工具:Vue CLI(维护态)→Vite(极速构建、热更新)。
  • 状态管理:Vuex → Pinia(轻量化、无嵌套、TS 友好)。
  • IDE 插件:Vetur → Volar(完善 TS 类型推导、语法校验)。
  • 静态站点:VuePress → VitePress。
  • JSX 支持:@vue/babel-preset-jsx → @vue/babel-plugin-jsx。
  • TS 校验:新增 vue-tsc 命令行类型校验工具。

Vue2 与 Vue3 核心差异

响应式原理(最核心差异)

Vue2:Object.defineProperty

遍历对象已有属性,劫持 getter/setter 实现响应式,存在先天缺陷:

  • 无法监听对象新增/删除属性,需依赖 $set/$delete
  • 无法监听数组下标修改、数组 length 变更,仅重写 7 个数组变异方法;
  • 需递归遍历嵌套对象,深层监听性能开销大;
  • 兼容 IE 浏览器,无法适配新语法特性。

Vue3:Proxy

劫持整个对象,返回全新代理对象,完美解决 Vue2 所有响应式问题:

  • 支持监听对象新增、删除属性,无需额外 API;
  • 原生监听数组下标、length 变更,支持所有数组操作;
  • 支持 Map、Set、WeakMap、WeakSet 数据结构响应式;
  • 惰性递归监听,优化深层对象性能;
  • 缺点:不兼容 IE 浏览器,无完整 polyfill 方案。

API 设计

选项式 API(Vue2 主打)

按功能选项拆分代码(data/methods/computed/watch),同一业务逻辑分散在不同模块,大型项目代码散乱、难以复用和维护,依赖 this 上下文,TS 类型推导薄弱。

组合式 API(Vue3 主推)

业务逻辑聚合代码,可抽离独立组合函数复用逻辑,无 this 依赖,原生适配 TS,压缩打包更友好。

逻辑复用示例(鼠标位置监听):

// 复用逻辑 useMousePosition.js
import { ref, onMounted, onUnmounted } from 'vue'
export default function useMousePosition() {
    const x = ref(0)
    const y = ref(0)
    const update = (e) => {
        x.value = e.pageX
        y.value = e.pageY
    }
    onMounted(() => window.addEventListener('mousemove', update))
    onUnmounted(() => window.removeEventListener('mousemove', update))
    return { x, y }
}
<!-- 组件使用 -->
<template>
    <div>鼠标坐标:{{ x }} {{ y }}</div>
</template>
<script setup>
    import useMousePosition from './useMousePosition'
    const { x, y } = useMousePosition()
</script>

选型建议:Vue3 兼容两种 API,小型项目可用选项式 API,中大型项目优先组合式 API,官方不废弃选项式 API。

模板与 DOM 变更

  • 多根节点支持:Vue2 模板必须单根节点,Vue3 支持 Fragments 多根节点;
  • v-if / v-for 优先级:Vue2 v-for 优先级更高,Vue3 v-if 优先级更高(规避无效循环,优化性能);
  • key 规则优化:v-if/v-else 分支无需手动 key,Vue3 自动生成唯一 key;<template v-for> 的 key 需写在 template 标签上;
  • v-bind 顺序敏感:Vue3 后声明的属性会覆盖先声明的同名属性,Vue2 固定优先级;
  • 移除 .native 修饰符:未在 emits 声明的事件,自动绑定到组件根元素。

生命周期变更

Vue3 组合式 API 生命周期需手动导入,命名统一增加 on 前缀,移除 beforeCreate、created(逻辑直接写在 setup 中):

Vue2 生命周期 Vue3 组合式生命周期
beforeCreate / created setup(替代,无需手动声明)
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestroy onBeforeUnmount
destroyed onUnmounted

v-model(重点)

Vue3 重构组件双向绑定,移除 .sync 和组件 model 选项,统一 v-model 规范:

  • 默认参数变更:Vue2 :value + @input → Vue3 :modelValue + @update:modelValue
  • 支持多 v-model:单个组件可绑定多个双向绑定;
  • 支持自定义修饰符:可自定义 capitalize、trim 等专属修饰符;
  • 语法糖简化:Vue3.4+ 新增 defineModel 宏,极简实现双向绑定。
<!-- Vue3 组件 v-model -->
<Child v-model="title" />
<!-- 编译等价于 -->
<Child :modelValue="title" @update:modelValue="val => title = val" />

<!-- 带参数、多绑定 -->
<Child v-model:title="name" v-model:content="desc" />

setup 核心语法

setup 是组合式 API 的核心入口,执行时机早于 beforeCreate,无组件实例 this

核心特性

  • this,无法访问 data、methods、computed;
  • 接收两个参数:props(响应式)、context(非响应式)
  • props 不可直接解构(丢失响应式),需配合 toRefs 解构;
  • context 包含 attrs、slots、emit,可直接解构使用;
  • 返回变量/方法可直接在模板使用,支持返回渲染函数。
import { ref, reactive, toRefs } from 'vue'
export default {
    props: ['title'],
    setup(props, { attrs, slots, emit }) {
        // 保留props响应式解构
        const { title } = toRefs(props)
        // 定义响应式数据
        const count = ref(0)
        const state = reactive({ name: 'Vue3' })
        // 定义方法
        const handleClick = () => count.value++
        // 暴露模板使用
        return { count, state, handleClick }
    }
}

重大破坏性变更

全局 API 重构(Tree-Shaking 友好)

移除 Vue2 全局静态 API,改为实例 API + 按需导入,解决全局污染、无法按需打包问题:

// Vue2
import Vue from 'vue'
Vue.component('xxx', xxx)
Vue.nextTick(() => {})

// Vue3
import { createApp, nextTick } from 'vue'
const app = createApp({})
app.component('xxx', xxx)

组件相关变更

  • 异步组件:必须通过 defineAsyncComponent 创建,废弃 Vue2 简易写法;
  • 函数式组件:移除 functional 配置,仅支持纯函数写法;
  • 插槽统一:移除$scopedSlots,所有插槽统一通过 $slots 访问(函数形式);
  • $listeners 移除:事件监听器合并入 $attrs,$attrs 新增包含 class、style。

样式与动画变更

  • transition 类名变更v-enterv-enter-fromv-leavev-leave-from
  • TransitionGroup:默认不渲染根 DOM 节点,无需冗余外层标签。

自定义指令变更

指令钩子对齐组件生命周期,重命名所有钩子,新增两个生命周期钩子:

  • bind → beforeMount;
  • inserted → mounted;
  • componentUpdated → updated;
  • unbind → unmounted;
  • 移除 update 钩子,新增 beforeUpdate、beforeUnmount 钩子;
  • 删除 binding.expression 属性。

彻底移除的 API

  • 事件相关:$on、$off、$once(废弃全局事件总线);
  • 响应式相关:$set、$delete(Proxy 无需手动处理);
  • 工具相关:filters 过滤器、keyCode 按键修饰符、inline-template;
  • 实例相关:$destroy、$children、propsData

常见问题

Vue3 如何实现 Vue2 created 生命周期?

Vue3 移除 beforeCreate、created 钩子,setup 函数执行时机等价于这两个钩子,初始化数据、请求、监听等逻辑直接写在 setup 顶层即可。

Vue3 监听数组为何不触发更新?

Vue3 的 watch 默认仅监听数组整体替换,数组内部元素修改、长度变更不会触发回调,如需监听内部变化,必须开启 deep: true

Vue3 相比 Vue2 性能提升的核心原因?

  • Proxy 惰性响应式,减少递归监听开销;
  • 虚拟 DOM 优化:静态节点标记、PatchFlag 精准 diff、事件缓存;
  • Tree-Shaking 按需打包,减小体积、提升运行速度;
  • v-if 优先级高于 v-for,规避无效循环渲染。

标准模板

<template>
    <a-modal
        v-model:visible="reactData.visible"
        title="标题"
        @cancel="handleCancel"
        @ok="handleOk"
    >
        <a-form
            ref="refForm"
            :model="reactData.formData"
            :rules="formRules"
            :label-col="{ span: 4 }"
            :wrapper-col="{ span: 20 }"
            autocomplete="off"
       >
            ...
        </a-form>
    </a-modal>
</template>
<script setup lang="ts">
    import { ref, defineEmits, defineProps, reactive, watch, computed } from 'vue';
    import type { FormInstance } from 'ant-design-vue';

    const formRules = {}
    const refForm = ref<FormInstance>()

    // props
    const props = defineProps({
        visible: {
            type: Boolean,
            required: true,
            default: false
        }
    })
    // emits
    const emits = defineEmits(['update:visible'])

    // data
    const reactData = reactive({
        loading: false,
        visible: false,
        formData: {
            keyword: '',
            birthMonth: ''
        }
    })

    // watch
    watch(() => props.visible, (newValue, oldValue) => {
        reactData.visible = newValue
    })

    // computed
    let isPasswordSame = computed(() => {
        return reactData.formData.password === reactData.formData.newPassword
    })

    // methods
    function handleCancel () {}
    function handleOk () {}
</script>

© lizhao all right reserved,powered by Gitbook文件修订时间: 2026-09-03 01:39:37

results matching ""

    No results matching ""