Vue 3 通过双向绑定将反应对象传递给组件
Posted
技术标签:
【中文标题】Vue 3 通过双向绑定将反应对象传递给组件【英文标题】:Vue 3 pass reactive object to component with two way binding 【发布时间】:2021-02-22 19:16:15 【问题描述】:我在 vue 3 中使用组合 API 对反应性组件进行双向绑定时遇到问题。
设置:
父调用代码为:
<template>
<h1> message.test </h1>
<Message v-model="message" />
</template>
<script>
import Message from '@/components/Message.vue';
import reactive from 'vue';
export default
name: 'Home',
components: Message ,
setup()
const message = reactive( test: '123' );
return
message
;
;
</script>
子组件代码为:
<template>
<label>
<input v-model="message" type="text" />
</label>
</template>
<script>
import computed from 'vue';
export default
props:
messageObj:
type: Object,
default: () => ,
,
,
emits: ['update:messageObj'],
setup(props, emit )
const message = computed(
get: () => props.messageObj.test,
set: (value) => emit('update:messageObj', value),
);
return
message,
;
,
;
</script>
问题:
加载组件时,对象的默认值会显示在输入字段中。 这是应该的,但是,当我更新输入框中的值时,父视图中的 H1 不会更新为新的输入框值。
我已经搜索了 *** 板和谷歌,但没有找到任何关于需要做什么来使对象反应的提示。
我阅读了reactivity documentation,但仍然没有找到任何解决我的问题的方法。
为了测试,我已将 message 更改为 ref 并使用这个单一的 ref 值,数据保持反应性,一切都按预期工作。
关于反应性对象不更新可能是什么问题的任何指针?
【问题讨论】:
目前还不清楚您传递给孩子的内容。v-model:test="message"
在其余代码的上下文中没有意义。您是将整个 reactive
还是仅将一个变量 (test
) 传递给孩子?
嗨,Daniel, v-model:test="message" 确实不对,它仍然是我忘记在另一次测试后改回的代码。它应该是js <template> <h1> message.test </h1> <Message v-model="message" /> </template>
【参考方案1】:
Here
<div id="app">
<h1> message.test </h1>
<child v-model="message"></child>
</div>
const createApp, reactive, computed = Vue;
// -------------------------------------------------------------- child
const child =
template: `<input v-model="message.test" type="text" />`,
props:
modelValue:
type: Object,
default: () => (),
,
,
emits: ['update:modelValue'],
setup(props, emit )
const message = computed(
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val),
);
return message ;
;
// ------------------------------------------------------------- parent
createApp(
components: child ,
setup()
const message = reactive( test: 'Karamazov' );
return message ;
).mount('#app');
【讨论】:
嗨,马特,这提供了一个解决方案,但它会将我希望在调用 vue 中拥有的一些逻辑转移到组件中。我的设置的目的是,我最终会在调用 vue 中获得逻辑,该逻辑将传递到添加到该页面的组件上,因此实际上使“哑”组件仅接收来自父级的数据并发出返回的更新以组件的形式。经过进一步的测试,我找到了解决方案。我将在对问题的回答中发表我的观察结果。【参考方案2】:解决方案和观察:
在调用组件的父视图中,如果您只需要传递对象中的一个值,您可以使用 v-model 并向该 v-model 添加参数。
<template>
<h1> message.test </h1>
<!-- <h1> message </h1> -->
<Message v-model:test="message" />
</template>
<script>
import Message from '@/components/Message.vue';
import reactive from 'vue';
export default
name: 'Home',
components: Message ,
setup()
const message = reactive( test: '123' );
return
message
;
;
</script>
然后,在接收组件中,您将在 props 中传递的对象的参数注册为对象。
<template>
<label>
<input v-model="message.test" type="text" />
</label>
</template>
<script>
import computed from 'vue';
export default
props:
test:
type: Object,
default: () =>
,
,
emits: ['update:test'],
setup(props, emit )
const message = computed(
get: () => props.test,
set: (value) => emit('update:test', value),
);
return
message,
;
,
;
</script>
如果您需要传递整个对象,您需要将其用作组件中的道具,名称为 modelValue。
与之前的代码相比,父代的变化:
<template>
<h1> message.test </h1>
<!-- <h1> message </h1> -->
<Message v-model="message" />
</template>
组件代码:
<template>
<label>
<input v-model="message.test" type="text" />
</label>
</template>
<script>
import computed from 'vue';
export default
props:
modelValue:
type: Object,
default: () =>
,
,
emits: ['update:modelValue'],
setup(props, emit )
const message = computed(
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
);
return
message,
;
,
;
</script>
【讨论】:
太棒了!示例非常干净,传入整个对象正是我想要的:谢谢: 向你致敬!它为我节省了很多时间。【参考方案3】:应该很简单,不需要计算。请参见下面的示例。
messageObj
在子组件中被替换为 message
以使发射工作(由于此演示中区分大小写,这将中断)
const app = Vue.createApp(
setup()
const message = Vue.reactive( test: '123' , foo: "bark");
return
message,
;
)
app.component('Message',
props:
message:
type: Object,
default: () => ,
,
,
emits: ['update:message'],
setup(props, emit )
const message = props.message;
return message ;
,
template: document.querySelector('#t_child')
)
app.mount('#app')
<script src="https://unpkg.com/vue@3.0.2/dist/vue.global.prod.js"></script>
<fieldset>
<div id="app">
<h1> message.test || message.foo </h1>
<fieldset><Message v-model:message="message"/></fieldset>
</div>
</fieldset>
<template id="t_child">
<label>
<h4>message</h4>
<input v-model="message.test" type="text" />
<input v-model="message.foo" type="text" />
</label>
</template>
【讨论】:
camelCase var 也咬了我,谢谢你指出这一点。 当我尝试使用此代码时,我收到了来自 ESLint 的消息:“在setup()
的根范围内从 props
获取值将导致该值失去反应性。” 以上是关于Vue 3 通过双向绑定将反应对象传递给组件的主要内容,如果未能解决你的问题,请参考以下文章