Vue3中从应用外部更新内部数据、调用方法的最佳方案
问题场景
初始化Vue 3应用的代码如下:
const app = createApp({ data() { return { some_id: 0 } } })
给页面字段配置自动补全组件后,需要在用户选中候选项时,把选项对应的id传入Vue应用。最初实现逻辑如下:
onSelectItem: ({label, value}) => { app.some_id = value; }
这套写法在Vue 2中可以正常运行,但升级到Vue 3之后,既无法通过这种方式直接修改应用内的数据,也无法在外部JavaScript函数中调用Vue实例的方法。
问题原因
本质是拿错了操作对象:Vue 3 中createApp返回的是应用实例,只提供全局配置、挂载这类应用级API,不会代理data中定义的响应式属性。直接修改应用实例的属性和修改普通JS对象没有区别,自然无法触发响应式更新,也访问不到实例上的方法。
解决方案
根据实际业务场景二选一即可:
方案1:最小改动,保存根组件实例引用
Vue 2中能直接修改实例属性,是因为当时拿到的是挂载后的根组件实例。Vue 3中mount方法执行后会返回根组件实例,保存这个引用就能沿用之前的写法:// 执行挂载时保存返回的根组件实例,#app替换为实际的挂载节点选择器 const vm = app.mount('#app') // 外部回调中操作这个根实例即可,行为和Vue 2完全一致 onSelectItem: ({label, value}) => { vm.some_id = value }这个方案改造成本极低,适合自动补全逻辑暂时无法迁移到Vue作用域内的场景。
方案2(推荐):逻辑内聚,在组件内部初始化自动补全
没必要硬在Vue作用域外部写回调,直接在组件的mounted生命周期里初始化自动补全组件,回调天然可以访问组件上下文,不需要暴露全局实例:const app = createApp({ data() { return { some_id: 0 } }, mounted() { // 在这里执行自动补全组件的初始化逻辑 initAutocomplete({ // 其余配置项保持原有写法即可 onSelectItem: ({label, value}) => { // 回调内this指向当前组件实例,直接修改数据就是响应式的 this.some_id = value } }) } }) app.mount('#app')这种写法所有逻辑都收敛在组件内部,不会污染全局作用域,后续维护不需要零散查找外部的实例引用,是Vue 3下更规范的实现方式。
内容的提问来源于stack exchange,提问作者Jasper Dent
相关产品推荐
相关产品推荐

