Vue3 的设计目标是什么?相比 Vue2 做了哪些关键优化?

刚开始用 Vue2 的时候,感觉就像拿到了一把顺手的新工具。简单、直观,做东西也特别快。

但随着项目越来越复杂,项目渐渐的也会遇到一些烦恼。组件的代码越写越长,相关的逻辑分散在data、methods、computed各种不同的地方,想复用一段功能也挺费劲的。同时打包后的文件也越来越大。

后来用了Vue3,可以说是完美的解决了我上面的几个痛点。

下面我们就来看下 vue3 到底做了哪些优化。

Vue 3.0 的四大设计目标

任何一次技术重构都有其核心目标,Vue 3 主要围绕以下四点展开:

  1. 更小:通过 Tree-shaking 等技术,让打包体积比 Vue 2 更小。
  2. 更快:优化虚拟 DOM,提升渲染和更新性能。
  3. 更易维护:采用 TypeScript 重写,代码结构更清晰模块化。
  4. 更好的扩展性:提供组合式 API 等新特性,应对复杂应用场景。

下面我们就来看看这些目标是如何具体实现的。


性能优化:底层引擎的重构

1. 响应式系统:Proxy 替代 Object.defineProperty

这是 Vue3 最核心的改进之一。

Vue2的响应式原理:

javascript 复制代码
// Vue2 使用 Object.defineProperty
const data = {};
Object.defineProperty(data, 'name', {
    get() {
        console.log('读取name');
        return '张三';
    },
    set(newVal) {
        console.log('设置name:', newVal);
    }
});

Vue2 的局限性:

  • 无法检测属性的添加和删除
  • 对数组的支持需要特殊处理
  • 初始化时需要递归遍历整个对象

Vue3 的解决方案:

javascript 复制代码
// Vue 3 使用 Proxy
const data = { name: '张三' };
const proxyData = new Proxy(data, {
    get(target, key) {
        console.log(`读取${key}`);
        return target[key];
    },
    set(target, key, value) {
        console.log(`设置${key}:`, value);
        target[key] = value;
        return true;
    },
    deleteProperty(target, key) {
        console.log(`删除${key}`);
        delete target[key];
        return true;
    }
});

Proxy 的优势:

  • 可以监听动态添加的属性
  • 支持数组索引修改、length 修改
  • 支持 Map、Set 等数据结构
  • 性能更好

2. 编译时优化:模板编译

Vue3 的编译器会分析模板,为动态内容添加标记。

html 复制代码
// 模板
<template>
  <div class="header">
    <img src="./logo.png" />
    <h1>{{ title }}</h1>
  </div>
</template>

Vue2 :每次渲染都重新创建 <img> 节点(虽然是静态的)。

Vue3 :编译时发现 <img> 永远不变,就把它缓存起来,只创建一次!

js 复制代码
// 编译后伪代码(简化)
const staticImg = createVNode('img', { src: './logo.png' })

function render() {
  return createVNode('div', { class: 'header' }, [
    staticImg, // 直接复用!
    createTextVNode(ctx.title) // 只有这里动态更新
  ])
}

3. Tree-shaking:按需引入

Vue3 的模块化设计使得未使用的功能不会被打包:

javascript 复制代码
import { createApp, h } from 'vue'; // 只引入需要的API

如果你不使用 transition 组件,它的代码就不会出现在最终打包文件中


开发体验的升级:组合式 API

这是 Vue3 在代码组织方式上的重大改进!

Vue2 Options API 的问题:

javascript 复制代码
export default {
    data() {
        return {
            users: [],
            searchQuery: '',
            loading: false
        }
    },
    methods: {
        fetchUsers() {
            // 获取用户数据
        },
        searchUsers() {
            // 搜索用户
        }
    },
    computed: {
        filteredUsers() {
            // 过滤用户
        }
    },
    mounted() {
        this.fetchUsers();
    }
}

同一个功能(用户管理)的逻辑被拆分到不同的选项中,组件复杂后难以维护。

Vue3 Composition API 的解决方案:

html 复制代码
<template>
  <div>
    <input v-model="searchQuery" placeholder="搜索用户">
    <div v-if="loading">加载中...</div>
    <UserList :users="filteredUsers" />
  </div>
</template>

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

// 用户管理功能 - 所有相关逻辑在一起
const users = ref([])
const searchQuery = ref('')
const loading = ref(false)

const filteredUsers = computed(() => {
  return users.value.filter(user => 
    user.name.includes(searchQuery.value)
  )
})

async function fetchUsers() {
  loading.value = true
  try {
    users.value = await api.getUsers()
  } finally {
    loading.value = false
  }
}

onMounted(() => {
  fetchUsers()
})

// 其他功能也可以这样组织...
// const posts = ref([])
// const fetchPosts = async () => { ... }
</script>

vue3 组合式函数:

javascript 复制代码
// composables/useUserManagement.js
import { ref, computed, onMounted } from 'vue'

export function useUserManagement() {
    const users = ref([])
    const searchQuery = ref('')
    const loading = ref(false)

    const filteredUsers = computed(() => {
        return users.value.filter(user => 
            user.name.includes(searchQuery.value)
        )
    })

    async function fetchUsers() {
        loading.value = true
        try {
            users.value = await api.getUsers()
        } finally {
            loading.value = false
        }
    }

    onMounted(fetchUsers)

    return {
        users,
        searchQuery,
        loading,
        filteredUsers,
        fetchUsers
    }
}
html 复制代码
<script setup>
// 在组件中使用
import { useUserManagement } from './composables/useUserManagement'

const { 
    users, 
    searchQuery, 
    loading, 
    filteredUsers,
    fetchUsers 
} = useUserManagement()
</script>

Vue3 同时支持 Options API 和 Composition API,你可以根据项目复杂度和个人偏好选择,甚至混合使用。


其他重要新特性

1. Teleport:任意传送

html 复制代码
<template>
  <div class="app">
    <button @click="showModal = true">打开弹窗</button>
    
    <!-- 将弹窗内容传送到 body 下 -->
    <Teleport to="body">
      <div v-if="showModal" class="modal">
        <h2>我是弹窗</h2>
        <button @click="showModal = false">关闭</button>
      </div>
    </Teleport>
  </div>
</template>

2. Fragments:多根节点支持

html 复制代码
<template>
  <!-- Vue 3 支持多个根节点 -->
  <header>头部</header>
  <main>主要内容</main>
  <footer>底部</footer>
</template>

3. Suspense:异步组件处理

html 复制代码
<template>
  <Suspense>
    <template #default>
      <AsyncComponent />
    </template>
    <template #fallback>
      <div>加载中...</div>
    </template>
  </Suspense>
</template>

<script setup>
import { defineAsyncComponent } from 'vue'
// 异步组件
const AsyncComponent = defineAsyncComponent(() => 
  import('./AsyncComponent.vue')
)
</script>

总结

特性对比 Vue 2 Vue 3 优势
响应式系统 Object.defineProperty Proxy 功能更完善,性能更好
代码组织 Options API Composition API 逻辑复用和组织更灵活
TypeScript 需要额外配置 原生支持 开发体验更好
包大小 全量引入 Tree-shaking 打包体积更小
新功能 有限 Teleport、Suspense等 开发能力更强

当然 Vue3 并没有抛弃过去,而是把选择权交给了我们:小项目可以用熟悉的 Options API 快速上手,大项目则可以借助 Composition API 和 TypeScript 更从容的组织代码。

本文首发于公众号:程序员刘大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

《重构了20个SpringBoot项目后,总结出这套稳定高效的架构设计》

《代码里全是 new 对象,真的很 Low 吗?我认真想了一晚》

《这 5 个冷门 HTML 标签,让我直接删了100 行 JS 代码》

《这 10 个 Vue3 性能优化技巧很实用,但很多项目都没用上》

相关推荐
亿元程序员2 小时前
亿元Cocos小游戏实战合集
前端
fengyucaihong_1232 小时前
vue加声音播放
javascript·vue.js·ecmascript
2503_928411562 小时前
12.26 小程序代码片段【添加WeaUI内容】
前端·微信小程序·小程序
麦麦大数据2 小时前
F066 vue+flask中医草药靶点知识图谱智能问答系统|中医中药医学知识图谱
vue.js·flask·知识图谱·中医·草药·成分知识图谱·靶点
鹏多多2 小时前
前端纯js实现图片模糊和压缩
前端·javascript·vue.js
长安即是故里2 小时前
搭建一个现代化视频聚合播放平台(含视频源)
前端·音视频·开源项目··部署教程
挖矿大亨2 小时前
c++中的函数调用运算符重载
前端·c++·算法
木辰風2 小时前
EasyExcel根据动态字段,进行导出excel文件
java·前端·excel
C_心欲无痕2 小时前
react - useReducer复杂状态管理
前端·javascript·react.js