Vue3是Vue2的升级版,不仅更快,还更好用。它解决了Vue2中一些让人头疼的问题,比如动态添加属性不响应、组件必须包在一个根元素里等等。
下面通过10个常见的对比例子,让你快速看懂Vue3到底新在哪儿、好在哪儿。
- 响应式系统:Object.defineProperty vs Proxy
Vue 2 无法监听动态添加的属性(除非用 Vue.set);Vue 3 可以直接响应。
javascript
// Vue 2 不会触发更新
this.obj.newProp = 'hello'
// Vue 2 正确方式
this.$set(this.obj, 'newProp', 'hello')
// Vue 3 直接赋值即可响应
this.obj.newProp = 'hello'
- Composition API(组合式 API)
javascript
<!-- Vue 2:Options API -->
<script>
export default {
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
}
</script>
<!-- Vue 3:Composition API -->
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>
- TypeScript 支持
javascript
// Vue 3 + TypeScript(能更好的支持)
<script setup lang="ts">
interface Props {
msg: string
}
const props = defineProps<Props>()
</script>
Vue 2 虽可通过 vue-class-component 或 vue-property-decorator 支持 TS,但配置复杂且类型推导弱。
- Fragment(多根节点)
javascript
<!-- Vue 2 报错:必须有一个根元素 -->
<template>
<header>Header</header>
<main>Main</main>
</template>
<!-- Vue 3 允许多个根节点 -->
<template>
<header>Header</header>
<main>Main</main>
</template>
- Teleport(传送门)
html
<template>
<button @click="open = true">Open Modal</button>
<Teleport to="body">
<div v-if="open" class="modal">
<p>Hello from Teleport!</p>
<button @click="open = false">Close</button>
</div>
</Teleport>
</template>
<script setup>
import { ref } from 'vue'
const open = ref(false)
</script>
Vue 2 需手动操作 DOM 或使用第三方库(如 portal-vue)。
- Suspense(异步组件加载)
javascript
<!-- 异步组件 -->
<!-- AsyncComponent.vue -->
<script setup>
const res = await fetch('/api/data')
const data = await res.json()
</script>
<template>
<div>{{ data }}</div>
</template>
html
<!-- 父组件 -->
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
Vue 2 无原生 ,需自行管理 loading 状态。
- 全局 API 变更
javascript
// Vue 2
Vue.component('MyButton', MyButton)
Vue.directive('focus', focusDirective)
// Vue 3
import { createApp } from 'vue'
const app = createApp(App)
app.component('MyButton', MyButton)
app.directive('focus', focusDirective)
app.mount('#app')
Vue 3 的应用实例彼此隔离,适合微前端或多实例场景。
- 生命周期钩子命名变化
javascript
// Vue 2
export default {
beforeDestroy() { /* cleanup */ },
destroyed() { /* final */ }
}
// Vue 3(Options API 写法)
export default {
beforeUnmount() { /* cleanup */ },
unmounted() { /* final */ }
}
// Vue 3(Composition API)
import { onBeforeUnmount, onUnmounted } from 'vue'
onBeforeUnmount(() => { /* cleanup */ })
onUnmounted(() => { /* final */ })
- v-model 多绑定
javascript
<!-- Vue 2:只能一个 v-model -->
<ChildComponent v-model="value" />
<!-- Child 内部约定 prop 名为 value,事件为 input -->
<!-- Vue 3:支持多个 -->
<ChildComponent
v-model:title="title"
v-model:content="content"
/>
<!-- Child 内部接收:props: ['title', 'content'] -->
<!-- 更新时触发:emit('update:title', newTitle) -->
- 显式声明 emits(推荐)
javascript
<!-- Vue 3 推荐写法 -->
<script setup>
const emit = defineEmits(['submit', 'cancel'])
const handleSubmit = () => emit('submit')
</script>
<!-- 或带验证 -->
<script setup>
const emit = defineEmits({
submit: (payload) => typeof payload === 'string',
cancel: null
})
</script>
Vue 2 中 $emit 无需声明,但不利于工具链和文档生成。
这些示例覆盖了 Vue2 和 Vue3 比较关键的差异点。通过代码对比,可以更清楚地看到 Vue3 在开发体验、性能、灵活性和工程化方面有明细的提升。