对比维度 | Vue2 选项式 API | Vue3 组合式 API(setup 函数 / setup 语法糖) |
|---|---|---|
代码组织方式 | 按选项类型组织:data、methods、computed、watch 等分散在不同选项中 | 按逻辑功能组织:相关变量、函数、计算属性和监听器集中在一起 |
访问响应式数据 | 通过 this 访问 data、methods 等成员 | 使用 ref 和 reactive 创建响应式数据,通过 .value 访问 ref 值(在 JS 中) |
模板中使用变量 | 直接使用 data 中定义的属性,无需 .value | 模板中使用 ref 时自动解包,无需 .value |
入口函数 | 组件选项对象本身(如 export default { ... }) | setup() 函数作为组件的入口,或使用 setup 语法糖自动执行 |
语法糖支持 | 不支持 setup | 支持 setup语法糖,省去 setup() 函数和 return,更简洁 |
this 指向 | 在 methods、computed 中可使用 this 指向组件实例 | 例 setup() 中没有 this,完全基于函数式编程思想 |
代码拆分灵活性 | 难以将同一功能的逻辑拆分到多个文件 | 可轻松将逻辑提取为独立的组合函数(composables)并跨组件复用 |
<template>
<div>
<h2>计数器: {{ count }}</h2>
<p>双倍值: {{ doubleCount }}</p>
<button @click="increment">+1</button>
<input v-model="search" placeholder="搜索用户" />
<ul>
<li v-for="user in filteredUsers" :key="user.id">
{{ user.name }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
count: 0,
search: '',
users: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
]
}
},
methods: {
increment() {
this.count++
}
},
computed: {
doubleCount() {
return this.count * 2
},
filteredUsers() {
return this.users.filter(u =>
u.name.toLowerCase().includes(this.search.toLowerCase())
)
}
},
watch: {
count(newVal) {
console.log('count changed:', newVal)
}
}
}
</script> <!-- Vue 3 - 标准 setup -->
<template>
<div>
<h2>计数器: {{ count }}</h2>
<p>双倍值: {{ doubleCount }}</p>
<button @click="increment">+1</button>
<input v-model="search" placeholder="搜索用户" />
<ul>
<li v-for="user in filteredUsers" :key="user.id">
{{ user.name }}
</li>
</ul>
</div>
</template>
<script>
import { ref, computed, watch } from 'vue'
export default {
setup() {
// 计数逻辑
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
const increment = () => {
count.value++
}
// 搜索逻辑
const search = ref('')
const users = ref([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
])
const filteredUsers = computed(() => {
return users.value.filter(u =>
u.name.toLowerCase().includes(search.value.toLowerCase())
)
})
// 监听
watch(count, (newVal) => {
console.log('count changed:', newVal)
})
// 返回给模板使用的变量和方法
return {
count,
doubleCount,
increment,
search,
filteredUsers
}
}
}
</script><!-- Vue 3 - 使用 <script setup>(顶级语法糖) -->
<script setup>
import { ref, computed, watch } from 'vue'
// 计数逻辑
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
const increment = () => count.value++
// 搜索逻辑
const search = ref('')
const users = ref([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
])
const filteredUsers = computed(() => {
return users.value.filter(u =>
u.name.toLowerCase().includes(search.value.toLowerCase())
)
})
// 监听
watch(count, (newVal) => {
console.log('count changed:', newVal)
})
</script>
<template>
<div>
<h2>计数器: {{ count }}</h2>
<p>双倍值: {{ doubleCount }}</p>
<button @click="increment">+1</button>
<input v-model="search" placeholder="搜索用户" />
<ul>
<li v-for="user in filteredUsers" :key="user.id">
{{ user.name }}
</li>
</ul>
</div>
</template>import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h => h(App)
}).$mount('#app')import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')钩子 | 执行时机 | 是否常用 |
|---|---|---|
beforeCreate | 实例初始化后,数据观测和事件配置之前 | 少用 |
created | 实例创建完成,数据已响应式,但 DOM 未挂载 | 常用于请求数据 |
beforeMount | 模板编译完成,即将挂载到 DOM | 较少使用 |
mounted | 组件已挂载到 DOM,可操作真实 DOM | 最常用之一 |
beforeUpdate | 数据更新时,虚拟 DOM 重新渲染前 | 可用于调试 |
updated | 虚拟 DOM 重新渲染并应用到 DOM 后 | 注意避免无限循环 |
beforeDestroy | 组件销毁前,仍可访问实例 | 清理定时器、事件监听等 |
destroyed | 组件已销毁,所有绑定解除,子实例也被销毁 | 常用 |
<!-- Vue 2 -->
<template>
<div id="app">
<h2 v-if="show">当前计数:{{ count }}</h2>
<button @click="count++">+1</button>
<button @click="show = false">销毁组件</button>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
count: 0,
show: true,
timer: null
}
},
beforeCreate() {
console.log(' beforeCreate: 实例还未初始化')
// 此时 this.$el 不存在,data 未代理
},
created() {
console.log('created: 实例创建完成', this.count)
// 可以发起网络请求
this.timer = setInterval(() => {
console.log('定时器运行中...')
}, 1000)
},
beforeMount() {
console.log(' beforeMount: 模板编译完成,DOM 未挂载')
},
mounted() {
console.log(' mounted: 组件已挂载到页面', this.$el)
// 可操作 DOM
},
beforeUpdate() {
console.log(' beforeUpdate: 数据变化,视图更新前')
},
updated() {
console.log(' updated: 视图已更新')
},
beforeDestroy() {
console.log(' beforeDestroy: 组件即将销毁')
// 必须手动清除副作用
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
destroyed() {
console.log('destroyed: 组件已完全销毁')
}
}
</script> 钩子 | 执行时机 | 是否常用 |
|---|---|---|
setup | 组件创建前,替代 beforeCreate 和 created,是 Composition API 的入口 | 必用,用于初始化数据和逻辑 |
onBeforeMount | 模板编译完成,即将挂载到 DOM | 较少使用,但可用于调试 |
onMounted | 组件已挂载到 DOM,可安全操作真实 DOM | 最常用之一,常用于请求数据、绑定事件、初始化第三方库 |
onBeforeUpdate | 数据更新时,虚拟 DOM 重新渲染前 | 可用于调试或获取更新前的 DOM 状态 |
onUpdated | 虚拟 DOM 重新渲染并应用到 DOM 后 | 注意避免在其中修改数据导致无限循环 |
onBeforeUnmount | 组件销毁前,实例仍可用,可清理副作用(如定时器、事件监听 | 常用于资源清理,防止内存泄漏 |
onUnmounted | 组件已完全卸载,所有绑定解除,子实例也被销毁 | 常用于确认销毁逻辑或日志记录 |
<!-- Vue 3 - 使用 <script setup> -->
<script setup>
import {
ref,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
const count = ref(0)
const show = ref(true)
let timer = null
// 模拟副作用:定时器
timer = setInterval(() => {
console.log('[Timer] 运行中...')
}, 1000)
// === 生命周期钩子 ===
console.log(' setup: 组件开始初始化')
onBeforeMount(() => {
console.log(' onBeforeMount: 即将挂载')
})
onMounted(() => {
console.log('onMounted: 组件已挂载', document.getElementById('app'))
})
onBeforeUpdate(() => {
console.log(' onBeforeUpdate: 视图更新前')
})
onUpdated(() => {
console.log(' onUpdated: 视图已更新')
})
onBeforeUnmount(() => {
console.log(' onBeforeUnmount: 组件即将卸载')
// 清理副作用
if (timer) {
clearInterval(timer)
timer = null
console.log(' 定时器已清除')
}
})
onUnmounted(() => {
console.log(' onUnmounted: 组件已完全卸载')
})
</script>
<template>
<div id="app">
<h2 v-if="show">当前计数:{{ count }}</h2>
<button @click="count++">+1</button>
<button @click="show = false">销毁组件</button>
</div>
</template>功能 | Vue 2 | Vue 3 | 区别说明 |
|---|---|---|---|
初始化前 | beforeCreate | setup() 开始处 | setup() 替代了 beforeCreate 和 created |
初始化后 | created | setup() 结束前 | Vue 3 推荐在 setup() 中统一处理初始化逻辑 |
挂载前 | beforeMount | onBeforeMount() | 名称一致,但 Vue 3 需导入使用 |
挂载后 | mounted | onMounted() | 用法相同,功能不变 |
更新前 | beforeUpdate | onBeforeUpdate() | 无本质变化 |
更新后 | updated | onUpdated() | 注意避免在其中修改响应式数据 |
销毁前 | beforeDestroy | onBeforeUnmount() | 命名变更,语义更准确(“卸载”而非“销毁”) |
销毁后 | destroyed | onUnmounted() | 同上,名称更规范 |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。