做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人参与
发表评论: