Vue2和Vue3全面对比

一个框架的升级往往代表有更新、更好用的技术支持,Vue2发展到Vue3也是如此,学习新版本框架,最快的方式就是首先熟悉框架升级前有的对比。在此之前更应该了解其背后的主要原因:

1、更好的性能:Vue3采用了全新的虚拟DOM算法和编译器优化,显著提高了性能表现;

2、更高的灵活性:Vue3引入了Composition API,使得代码的灵活性和可复用性大幅提升;

3、改进的开发者体验:Vue3从设计上就考虑了TypeScript,提供了更完善的类型定义,提升了开发体验和代码的可维护性;

4、Composition API:Composition API是Vue3的一大亮点,使得开发者能够更灵活地组织和重用代码;

5、优化的Vue Router和Vuex:Vuex在Vue3中引入了更灵活的模块化设计,使得状态管理更加易于维护和扩展;

6、对现代JavaScript的支持:Vue3全面支持现代JavaScript特性,使得开发者能够利用最新的语言特性进行开发。

 

Vue3相对于Vue2在性能、开发者体验、代码灵活性等方面进行了多方面的改进,使得开发者能够更高效地构建现代化的Web应用。

 

1. 应用创建

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

全局构造函数

new Vue({ router, store }).$mount('#app')

createApp 工厂函数

createApp(App).use(router).use(pinia).mount('#app')

全局 API 挂在 Vue

Vue.component(), Vue.directive(), Vue.mixin()

实例级别挂载

app.component(), app.directive(), app.mixin()

 

2. 响应式数据

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

data 选项

data() { return { count: 0 } }

ref()

const count = ref(0); count.value++

data 选项

data() { return { user: { name: '' } } }

reactive()

const user = reactive({ name: '' }); user.name = 'xx'

computed 选项

computed: { double() { return this.count * 2 } }

computed() 函数

const double = computed(() => count.value * 2)

watch 选项

watch: { count(v) { console.log(v) } }

watch() 函数

watch(count, (v) => console.log(v))

watchEffect()

watchEffect(() => console.log(count.value))

shallowRef / shallowReactive

const list = shallowRef([]) 性能优化

toRefs() 解构保持响应式

const { name, age } = toRefs(user)

Object.defineProperty

无法检测属性新增/删除、数组索引

Proxy

全面拦截,无上述限制

Vue.set() / this.$set()

this.$set(obj, 'key', value)

不需要,直接赋值

obj.key = value

Vue.delete() / this.$delete()

this.$delete(obj, 'key')

不需要,直接 delete

delete obj.key

 

3. 模板语法

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

单根节点

<template><div>...</div></template>

多根节点(Fragment

<template><h1>A</h1><p>B</p></template>

v-model

<Input v-model="val" />

v-model + 参数名

<Input v-model:title="t" v-model:content="c" />

.sync 修饰符

<Dialog :visible.sync="show" />

v-model:xxx 替代

<Dialog v-model:visible="show" />

.native 修饰符

<Input @click.native="fn" />

移除,默认就是

<Input @click="fn" />

filters 过滤器

{{ date | formatDate }}

移除,用方法/computed

{{ formatDate(date) }}

$listeners

v-on="$listeners"

合并到 $attrs

v-bind="$attrs" 同时包含事件

 

4. 生命周期

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

created

created() { this.fetch() }

setup 顶层直接写

fetch() 直接调用

mounted

mounted() { ... }

onMounted()

onMounted(() => { ... })

destroyed

destroyed() { ... }

onUnmounted()

onUnmounted(() => { ... })

beforeDestroy

beforeDestroy() { ... }

onBeforeUnmount()

onBeforeUnmount(() => { ... })

onRenderTracked()

调试:哪些响应式被依赖

onRenderTriggered()

调试:哪些响应式触发更新

 

5. 事件通信

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

$on / $off / $once

this.$on('event', fn)

移除,用第三方库

import mitt from 'mitt'; emitter.on('event', fn)

$emit

this.$emit('change', val)

emit() setup

const emit = defineEmits(['change']); emit('change', val)

$listeners 独立存在

v-on="$listeners"

合并到 $attrs

不再需要单独传递

 

6. 组件通信

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

props + this.$emit

props: ['val']; this.$emit('update', v)

defineProps + defineEmits

const p = defineProps(['val']); const e = defineEmits(['update'])

provide / inject

provide() { return { theme: this.theme } }

provide() / inject() 函数

provide('theme', ref('dark')); const t = inject('theme')

$parent / $children

this.$parent.msg; this.$children[0]

移除 $children

ref provide/inject 替代

$refs

this.$refs.input.focus()

ref() + 模板 ref

const input = ref(); input.value.focus()

$attrs / $listeners

inheritAttrs: false; v-bind="$attrs"; v-on="$listeners"

$attrs 包含事件

inheritAttrs: false; v-bind="$attrs"

EventBus

Vue.prototype.$bus = new Vue()

mitt 等事件库

const bus = mitt(); bus.emit('x'); bus.on('x', fn)

 

7. 插槽

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

默认插槽

<slot />

不变

<slot />

具名插槽

<slot name="header" /> + <template #header>

统一用 # 语法

<slot name="header" /> + <template #header>

作用域插槽

<slot :item="item" /> + <template #default="scope">

不变

<slot :item="item" /> + <template #default="{ item }">

 

8. 组合式函数 / Mixins

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

mixins

mixins: [myMixin]

移除,用 Composables

const { count, increment } = useCounter()

全局 mixin

Vue.mixin({...})

不推荐

抽成 composable 函数

逻辑复用

mixins 有命名冲突、来源不清

Composable

function useCounter() { const c = ref(0); return { c } }

 

9. 自定义指令

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

对象形式

Vue.directive('focus', { bind(el) {}, inserted(el) {} })

名称变化 + 钩子合并

app.directive('focus', { created(el) {}, mounted(el) {} })

bind -> created

bind(el) {}

created(el) {}

元素创建时

inserted -> mounted

inserted(el) {}

mounted(el) {}

元素插入 DOM

组件内指令

directives: { focus: { inserted(el) { el.focus() } } }

directives: { focus: { mounted(el) { el.focus() } } }

钩子名变化

 

10. Teleport / Suspense

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

无,弹窗受父级影响

需手动 document.body.appendChild

Teleport

<Teleport to="body"><Modal /></Teleport>

无异步组件加载态

需手动 loading 判断

Suspense

<Suspense><template #default><Async /></template><template #fallback><Loading /></template></Suspense>

 

11. 路由

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

new VueRouter()

new VueRouter({ routes })

createRouter()

const r = createRouter({ history, routes })

mode: 'history'

mode: 'history'

history 选项

history: createWebHistory()

mode: 'hash'

mode: 'hash'

history 选项

history: createWebHashHistory()

this.$route / this.$router

this.$route.params.id

useRoute() / useRouter()

const route = useRoute(); route.params.id

this.$router.push()

this.$router.push('/home')

router.push()

const router = useRouter(); router.push('/home')

全局前置守卫

router.beforeEach((to, from, next) => {})

返回值或 next

router.beforeEach((to) => { return '/login' })

 

12. 状态管理

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

Vuex Store

new Vuex.Store({ state, mutations, actions, getters })

Pinia

const useX = defineStore('x', () => { ... })

this.$store.state

this.$store.state.count

直接调用

const x = useX(); x.count

this.$store.commit()

this.$store.commit('increment')

不需要 mutations

x.increment()

this.$store.dispatch()

this.$store.dispatch('fetch')

直接调用 action

x.fetch()

mapState / mapGetters

...mapState(['count'])

不需要,直接解构

const { count } = storeToRefs(x)

modules 嵌套

modules: { user: { ... }, order: { ... } }

每个文件一个 store

useUserStore(), useOrderStore()

 

13. 样式

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

scoped

<style scoped>

不变

<style scoped>

深度选择器

::v-deep .child /deep/ .child

:deep(.child)

:deep(.child)

全局样式注入

通过 webpack prependData 引入公共 scss

Vite css.preprocessorOptions

additionalData: '@import "@/styles/base.scss"'

 

14. 内置组件变化

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

<transition>

<transition name="fade"><div v-if="show" /></transition>

不变

同左

<transition-group>

<transition-group tag="ul"><li v-for="..." /></transition-group>

移除 tag 属性

默认渲染为 fragment,不再需要 tag

<keep-alive>

<keep-alive><router-view /></keep-alive>

用法不变

同左

 

15. 移除的 API

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

Vue.set()

Vue.set(obj, 'key', val)

移除

直接赋值 obj.key = val

Vue.delete()

Vue.delete(obj, 'key')

移除

delete obj.key

Vue.filter()

Vue.filter('cap', (v) => v.toUpperCase())

移除

用方法或 computed

$on / $off / $once

this.$on('evt', fn)

移除

mitt 等事件库

$children

this.$children[0]

移除

ref / provide

$listeners

this.$listeners

移除

合并到 $attrs

$scopedSlots

this.$scopedSlots.default

移除

统一为 $slots

$destroy

this.$destroy()

移除

不再手动销毁

.native 修饰符

@click.native="fn"

移除

直接 @click="fn"

.sync 修饰符

:val.sync="x"

移除

v-model:val="x"

filters

| filterName

移除

{{ fn(val) }}

 

16. 构建与配置

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

Webpack

vue-cli-service 内置

Vite + esbuild

vite 开发,Rollup 生产构建

入口 HTML public/

public/index.html 模板

入口 HTML 在根目录

index.html 直接入口

Babel 转译

babel.config.js

esbuild 转译

无需 babel.config.js

环境变量

VUE_APP_* 前缀

VITE_* 前缀

import.meta.env.VITE_XXX

配置文件

vue.config.js (js)

vite.config.ts (ts)

TypeScript 原生支持

热更新

重编译依赖链

HMR 精确更新

只更新变更模块

 

17. 性能

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

虚拟 DOM 全量 diff

每次渲染对比整棵树

Patch Flag 标记

diff 动态节点,静态节点跳过

静态节点每次重建

<span>静态文本</span> 每次重新创建

静态提升

静态节点只创建一次,后续复用

包体积 ~23KB gzip

包体积 ~13KB gzip

减少 41%

tree-shaking

import Vue from 'vue' 全量引入

全局 tree-shakeable

import { ref } from 'vue' 按需引入

 

18. 生态依赖对比

Vue 2 功能

Vue 2 案例

Vue 3 功能

Vue 3 案例

框架

vue@^2.7

框架

vue@^3.5

构建工具

@vue/cli-service (Webpack)

构建工具

vite@^5

语言

JavaScript

语言

TypeScript

路由

vue-router@^3

路由

vue-router@^4

状态管理

vuex@^3

状态管理

pinia@^2/3

PC UI

element-ui@^2

PC UI

element-plus@^2

移动端 UI

vant@^2

移动端 UI

vant@^4

HTTP

axios@^0.21 + qs

HTTP

axios@^1

日期处理

moment

日期处理

date-fns

函数工具

underscore / lodash

函数工具

es-toolkit

组合式函数

组合式函数

@vueuse/core

模式匹配

模式匹配

ts-pattern

Cookie

cookiejs + js-cookie

Cookie

universal-cookie

移动端适配

postcss-plugin-px2rem

移动端适配

postcss-px-to-vw

CSS 方案

sass / less

CSS 方案

sass + unocss

自动导入

自动导入

unplugin-auto-import + unplugin-vue-components

ESLint

eslint@^7 + eslint-plugin-vue

ESLint

@antfu/eslint-config

 

posted on 2026-05-10 16:36  JustItIs  阅读(28)  评论(0)    收藏  举报

导航