Vue选项式API中使用provide实现基础类型双向绑定的问题
解决选项式API中provide传递基础类型的响应式双向绑定问题
问题原因
在选项式API中,data()声明的基础类型变量(如示例中的flag)虽然是响应式的,但直接在provide()中传递this.flag时,实际传递的是自动解包后的原始值,而非响应式包装对象。子组件inject获取到的只是该原始值的副本,修改副本不会触发父组件的响应式更新,因此无法实现双向同步。而对象类型是引用传递,修改属性会直接作用于原引用,所以能正常同步。
解决方案
方案1:将基础类型包装进对象传递
通过把基础类型变量放入对象中,利用引用传递的特性实现响应式同步。
父组件修改后代码:
<script> import Child from './Child.vue' export default { components: { Child }, data() { return { message: {"name":"hello"}, // 将flag包装进state对象 state: { flag: false } } }, methods:{ change() { this.state.flag = !this.state.flag } }, provide() { return { message: this.message, state: this.state } } } </script> <template> <div> <input v-model="message.name"> <!-- 按钮事件改为@click,原@change是输入框事件 --> <button @click="change">click</button> {{ state.flag }} </div> <Child /> </template>
子组件修改后代码:
<script> export default { inject:["message","state"], methods:{ change() { this.state.flag = !this.state.flag } } } </script> <template> <div> <input v-model="message.name"> <button @click="change">click</button> {{ state.flag }} </div> </template>
方案2:用computed包装响应式变量
利用computed返回响应式Ref对象的特性,通过getter和setter实现双向同步。
父组件修改后代码:
<script> import Child from './Child.vue' import { computed } from 'vue' export default { components: { Child }, data() { return { message: {"name":"hello"}, flag: false } }, methods:{ change() { this.flag = !this.flag } }, provide() { return { message: this.message, // 用computed包装并定义setter flag: computed({ get: () => this.flag, set: (val) => { this.flag = val } }) } } } </script> <template> <div> <input v-model="message.name"> <button @click="change">click</button> {{ flag }} </div> <Child /> </template>
子组件修改后代码:
<script> export default { inject:["message","flag"], methods:{ change() { // 直接修改Ref的value属性 this.flag.value = !this.flag.value } } } </script> <template> <div> <input v-model="message.name"> <button @click="change">click</button> {{ flag }} </div> </template>
注意点
- 原代码中按钮使用
@change事件是错误的,按钮的点击事件应为@click,已在方案中修正。
内容的提问来源于stack exchange,提问作者Altynai
相关产品推荐
相关产品推荐

