Vue2 与 Vue3 全面对比
Vue2 与 Vue3 全面对比
Vue3 于 2020 年 9 月正式发布,相比 Vue2 带来了许多重大改进。本文从多个维度全面对比 Vue2 和 Vue3,帮助开发者理解两者的区别,并为迁移提供参考。
一、性能对比
1. 打包体积优化
Vue2:
Vue3:
// Vue2:全部导入
import Vue from 'vue';
// Vue3:按需导入
import { ref, reactive, computed } from 'vue';2. 渲染性能
Vue2:
Vue3:
// Vue2 编译结果
function render() {
return h('div', { id: 'app' }, [
h('h1', {}, this.title),
h('p', { class: 'static' }, 'Static text')
]);
}
// Vue3 编译结果(带优化)
const _hoisted_1 = h('p', { class: 'static' }, 'Static text');
function render() {
return h('div', { id: 'app' }, [
h('h1', {}, this.title),
_hoisted_1
]);
}3. 响应式性能
Vue2(Object.defineProperty):
Vue3(Proxy):
二、API 设计对比
1. Options API vs Composition API
Vue2 - Options API:
按选项(data、methods、computed、watch)组织代码。
<script>
export default {
data() {
return {
count: 0,
user: null
};
},
methods: {
increment() {
this.count++;
}
},
computed: {
doubleCount() {
return this.count * 2;
}
},
mounted() {
this.fetchUser();
}
};
</script>Vue3 - Composition API:
按功能组织代码,相关逻辑集中在一起。
<script setup>
import { ref, computed, onMounted } from 'vue';
const count = ref(0);
const user = ref(null);
const increment = () => {
count.value++;
};
const doubleCount = computed(() => count.value * 2);
const fetchUser = async () => {
// 获取用户
};
onMounted(() => {
fetchUser();
});
</script>对比分析:
| 特性 | Options API | Composition API |
|------|-------------|-----------------|
| 代码组织 | 按选项分散 | 按功能集中 |
| 逻辑复用 | mixins | composables |
| TypeScript 支持 | 一般 | 优秀 |
| 学习曲线 | 低 | 较高 |
2. 生命周期对比
| Vue2 | Vue3 | 说明 |
|------|------|------|
| beforeCreate | setup() | 实例创建前 |
| created | setup() | 实例创建后 |
| beforeMount | onBeforeMount | 挂载前 |
| mounted | onMounted | 挂载后 |
| beforeUpdate | onBeforeUpdate | 更新前 |
| updated | onUpdated | 更新后 |
| beforeDestroy | onBeforeUnmount | 卸载前 |
| destroyed | onUnmounted | 卸载后 |
// Vue2 生命周期
export default {
beforeCreate() {
console.log('beforeCreate');
},
created() {
console.log('created');
},
mounted() {
console.log('mounted');
},
beforeDestroy() {
console.log('beforeDestroy');
}
};
// Vue3 生命周期
import {
onBeforeMount,
onMounted,
onBeforeUnmount,
onUnmounted
} from 'vue';
export default {
setup() {
onBeforeMount(() => {
console.log('onBeforeMount');
});
onMounted(() => {
console.log('onMounted');
});
onBeforeUnmount(() => {
console.log('onBeforeUnmount');
});
onUnmounted(() => {
console.log('onUnmounted');
});
}
};三、响应式 API 对比
1. 数据定义
Vue2:
export default {
data() {
return {
count: 0,
user: {
name: 'Alice',
age: 25
}
};
}
};Vue3:
import { ref, reactive } from 'vue';
// ref:适合基本类型
const count = ref(0);
// reactive:适合对象
const user = reactive({
name: 'Alice',
age: 25
});2. 计算属性
Vue2:
export default {
data() {
return {
firstName: 'John',
lastName: 'Doe'
};
},
computed: {
fullName() {
return this.firstName + ' ' + this.lastName;
}
}
};Vue3:
import { ref, computed } from 'vue';
const firstName = ref('John');
const lastName = ref('Doe');
const fullName = computed(() => {
return firstName.value + ' ' + lastName.value;
});3. 监听器
Vue2:
export default {
data() {
return {
count: 0
};
},
watch: {
count(newVal, oldVal) {
console.log('count changed:', newVal, oldVal);
}
}
};Vue3:
import { ref, watch, watchEffect } from 'vue';
const count = ref(0);
// 监听单个源
watch(count, (newVal, oldVal) => {
console.log('count changed:', newVal, oldVal);
});
// watchEffect:自动追踪依赖
watchEffect(() => {
console.log('count:', count.value);
});四、组件系统对比
1. 组件定义
Vue2:
// 全局注册
Vue.component('my-component', {
template: '<div>My Component</div>'
});
// 局部注册
export default {
components: {
MyComponent
}
};Vue3:
import { defineComponent } from 'vue';
import MyComponent from './MyComponent.vue';
// defineComponent(可选,用于类型推断)
export default defineComponent({
components: {
MyComponent
}
});
// <script setup> 自动注册
<script setup>
import MyComponent from './MyComponent.vue';
</script>2. Props 和 Emits
Vue2:
<script>
export default {
props: {
title: String,
count: {
type: Number,
default: 0
}
},
methods: {
handleClick() {
this.$emit('click', { id: 1 });
}
}
};
</script>Vue3:
<script setup>
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
title: String,
count: {
type: Number,
default: 0
}
});
const emit = defineEmits(['click', 'update']);
const handleClick = () => {
emit('click', { id: 1 });
};
</script>五、状态管理对比
Vuex 3 vs Vuex 4 vs Pinia
Vuex 3(Vue2):
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
increment({ commit }) {
commit('increment');
}
}
});Vuex 4(Vue3):
import { createStore } from 'vuex';
export default createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
increment({ commit }) {
commit('increment');
}
}
});Pinia(Vue3 推荐):
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++;
}
},
getters: {
doubleCount: (state) => state.count * 2
}
});
// 组件中使用
const counterStore = useCounterStore();
counterStore.increment();六、Vue Router 对比
Vue Router 3(Vue2):
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
component: Home
}
]
});Vue Router 4(Vue3):
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: Home
}
]
});七、迁移指南
从 Vue2 迁移到 Vue3
1. 更新依赖:
{
"dependencies": {
"vue": "^3.0.0",
"vue-router": "^4.0.0",
"vuex": "^4.0.0"
}
}2. 全局 API 变更:
// Vue2
import Vue from 'vue';
Vue.use(Plugin);
Vue.component('MyComponent', MyComponent);
// Vue3
import { createApp } from 'vue';
const app = createApp(App);
app.use(Plugin);
app.component('MyComponent', MyComponent);
app.mount('#app');3. 模板变更:
4. 移除的特性:
八、最佳实践建议
1. 新项目:
2. 老项目迁移:
3. 代码组织:
总结
| 维度 | Vue2 | Vue3 |
|------|------|------|
| 性能 | 较好 | 更优 |
| 体积 | 较大 | 更小 |
| API | Options API | Composition API |
| 响应式 | Object.defineProperty | Proxy |
| TypeScript | 支持一般 | 支持优秀 |
| 多根节点 | 不支持 | 支持 |
| 状态管理 | Vuex 3 | Pinia |
| 路由 | Vue Router 3 | Vue Router 4 |