做Vue项目的时候,很多从Vue2转过来的同学都会纠结:Vue3里还能像Vue2那样直接用this吗?这事儿得拆开了说,因为Vue3的设计思路和API变化,让this的用法和地位跟之前大不一样,今天就从变化原因、替代方案、实际场景这些角度,把Vue3里的this讲明白。
Vue2里this几乎是“万能入口”——能拿data里的变量、调用methods里的方法、访问计算属性,还能操作路由和状态管理,但这种设计在复杂组件里容易出问题:this指向不明确(比如在定时器、回调里容易丢指向);Options API靠this把所有东西“串”起来,导致代码逻辑分散(比如一个功能的代码可能分散在data、methods、computed里),维护起来费劲。
Vue3推出组合式API(Composition API),就是想解决逻辑复用和代码组织的问题,组合式API更强调“函数式”的写法,把相关逻辑聚在一起,这时候再依赖this就不合适了——因为组合式API的函数里,this不一定指向组件实例(比如在setup函数里,this是undefined),所以Vue3通过调整API设计,弱化了this的存在感,用更明确的方式来获取组件资源。
Vue3里怎么替代this的常见用法?
访问组件数据:从this.xxx到响应式API
Vue2里用this.count访问data里的变量,Vue3的组合式API里,得用ref或reactive先把数据变成响应式,再直接访问,举个例子:
// Vue2写法
export default {
data() {
return { count: 0 }
},
methods: {
add() {
this.count++ // 依赖this
}
}
}
// Vue3组合式API写法
import { ref } from 'vue'
export default {
setup() {
const count = ref(0) // 用ref创建响应式数据
const add = () => {
count.value++ // 直接操作count的value,不需要this
}
return { count, add } // 暴露给模板用
}
}这里核心是响应式数据的创建和访问方式变了——ref包装后要通过.value访问(模板里不用,JS里得用),reactive包装的对象则可以直接点属性(但要注意深响应式和解构问题)。
调用方法:从this.xxx()到函数作用域
Vue2里调用方法靠this.handleClick(),Vue3组合式API里,方法就是普通函数,定义在哪就从哪调用,比如在setup里定义的函数,直接调用就行:
// Vue3里在setup内调用方法
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
const add = () => {
count.value++
logCount() // 直接调用同作用域的函数
}
const logCount = () => {
console.log(count.value)
}
return { add }
}
}这种写法更符合JavaScript的函数作用域逻辑,不用再依赖this来“跨区域”找方法,代码的内聚性更强。
访问路由、状态管理等全局对象:用工具函数
Vue2里拿路由要this.$router,拿Vuex要this.$store,Vue3里得换方式:
路由:在组合式API里,用
useRouter和useRoute(需要先安装Vue Router 4+)import { useRouter, useRoute } from 'vue-router' export default { setup() { const router = useRouter() const route = useRoute() const goHome = () => { router.push('/') // 替代this.$router.push } return { goHome } } }Vuex:用
useStore(需要Vuex 4+)import { useStore } from 'vuex' export default { setup() { const store = useStore() const fetchData = () => { store.dispatch('getData') // 替代this.$store.dispatch } return { fetchData } } }这种“按需引入”的方式,比Vue2里靠
this挂载全局对象更清晰,也避免了this指向混乱的风险。
访问组件实例:getCurrentInstance
如果非要在组合式API里拿到组件实例(比如访问自定义指令、老项目里的this遗留逻辑),Vue3提供了getCurrentInstance方法:
import { getCurrentInstance } from 'vue'
export default {
setup() {
const instance = getCurrentInstance()
// instance相当于Vue2里的this,但要注意:
// 生产环境下instance可能被树摇优化,某些属性不可用
// 尽量优先用组合式API的标准方法,少依赖实例
console.log(instance.proxy) // 类似Vue2的this,能访问props、attrs等
}
}但官方不推荐滥用getCurrentInstance,因为这会让代码回到“依赖黑盒实例”的老路,违背组合式API的设计初衷。
Vue3中this完全不能用了吗?
也不是,如果用选项式API(Options API)写Vue3代码,this依然可以用,用法和Vue2几乎一样:
// Vue3选项式API写法
export default {
data() {
return { count: 0 }
},
methods: {
add() {
this.count++ // 这里this还能用
}
}
}Vue3对选项式API做了兼容,所以如果团队更习惯Options API的写法,this的使用方式和Vue2差别不大,但要注意:选项式API里的this,在setup函数中还是undefined(因为setup是在组件实例创建前执行的)。
常见误区:把Vue3的this和Vue2混着用
很多同学刚学Vue3时,容易犯“缝合怪”错误——在setup里试图用this,或者在选项式API里乱入组合式API的写法。
// 错误示范:setup里用this
export default {
setup() {
this.count = 1 // 报错!setup里this是undefined
},
data() { return { count: 0 } }
}
// 错误示范:选项式API里用ref却忘改.value
export default {
data() { return { count: ref(0) } }, // 没必要!data里的变量本身就是响应式的
methods: {
add() {
this.count.value++ // 多此一举,选项式API里直接this.count++就行
}
}
}核心要明白:组合式API和选项式API是两套逻辑,别把响应式API和this的用法硬凑在一起,组合式API走“函数式、显式引入”的路子,选项式API保留“this聚合资源”的模式,选一种风格写到底更不容易出错。
Vue3的this,变的是逻辑,不变的是目的
Vue3调整this的用法,不是为了折腾开发者,而是为了让代码更易维护、逻辑更内聚,如果用选项式API,this的体验和Vue2差不多;如果用组合式API,要学会用ref/reactive管理响应式数据,用useRouter、useStore等工具函数替代全局对象访问,用函数作用域替代this的跨域调用。
理解背后的设计逻辑(组合式API的函数式、逻辑聚合),比死记“this还能不能用”更重要,毕竟框架的变化是为了解决实际开发里的痛点,跟着设计思路走,写代码时的困惑自然会少很多~
(延伸思考:如果团队要做Vue2到Vue3的迁移,怎么处理大量依赖this的老代码?可以先从选项式API兼容写法入手,逐步往组合式API重构;或者用Vue3的兼容模式,让老代码先跑起来,再分批优化。)


网友回答文明上网理性发言 已有0人参与
发表评论: