英文:
Vue3 Prop passing to data item to be able to manipulate values, not modelling data item actually, why?
问题
我正在使用vue3,想知道如何正确传递数据。
我的组件结构是一个表格(通过pinia存储加载项目):XTableComponent
XTableComponent
有一个子组件:XModalComponent
。在渲染的表格中,每一行都有一个按钮。点击该按钮会将当前项目存储在一个数据项中。
XTableComponent
:
<template>
<!-- 在每一行中都有一个带有 @click 的按钮,将当前项目作为参数 -->
<x-modal-component v-if="currentItem" :item="currentItem" ref="x-modal"></x-modal-component>
</template>
<script>
export default {
data: () => {
return {
currentItem: {},
itemListStore: useItemListStore()
}
},
computed: {
itemList() {
return this.itemListStore.list
}
},
methods: {
showModal(item){
this.currentItem = item
this.$refs['x-modal'].show()
}
}
}
</script>
我的子组件看起来有点像这样:
XModalComponent
:
<template>
<!-- ... -->
<input v-model:value="innerItem.something" type="text">
<button @click="save">保存</button>
</template>
<script>
export default {
props: {
item: Object
},
data: () => {
return {
innerItem: {}
}
},
mounted() {
this.innerItem = this.item
},
methods: {
save() {
console.log(this.innerItem) // 这不会显示“something”的修改值
}
}
}
</script>
现在,如果我在子组件中修改输入并触发点击事件,值不会更改在我的数据项中...
在vue3中,我在响应性、代理和传递 props 方面做错了什么?
p.s. 这里的代码有点伪代码,所以请原谅我拼写错误或明显遗漏的部分。
p.p.s. 我对vue2相当熟悉,所以也许我混合了一些概念。请告诉我。
p.p.p.s. 我的表格渲染正确,模态窗口看起来也不错。我已经仔细检查了所有名称和拼写错误。
英文:
I am using vue3 and wonder how to pass data the correct way.
My Component structure is one table (items loaded via pinia store): XTableComponent
The XTableComponent
has a child: XModalComponent
. In the rendered table I have a button in each row. @click
on that stores the current item in a data item
XTableComponent
:
<template>
...that mentioned table in each line a button with @click and the item in the iteration as param
<x-model-component v-if="currentItem" :item="currentItem ref="x-modal"></x-modal-component>
</template>
<script>
export default {
data: () => {
return {
currentItem: {},
itemListStore: useItemListStore()
}
},
computed: {
itemList() {
return this.itemListStore.list
}
methods: {
showModal(item){
this.currentItem = item
this.$refs['x-modal'].show()
}
}
}
</script>
My Child component looks a bit like this:
XModalComponent
:
<template>
....
<input v-model:value="innerItem.something" type="text">
<button @click="save">save</button>
</template>
<script>
export default {
props: {
item: Object
},
data: () => {
return {
innerItem: {}
}
}
mounted() {
this.innerItem = item
},
methods: {
save() {
console.log(this.innerItem) //this does not show the manipulated value of `something`
}
}
}
</script>
Now, if I manipulate the input in my child component, and trigger a click event, the value does not get changed on my data item ...
what did I get wrong in vue3 with reactiveness, proxeis and passing props?
p.s. my code is kind of pseude code here, so please be fair with me on typos, or obvious parts
that are missing
p.p.s. I am used to vue2 quite well, so maybe I mix concepts. please tell me that too.
p.p.p.s. my table renders correctly, the modal looks fine. i double checked all names and typos.
答案1
得分: 1
因此,正如我们所发现的,问题出在innerItem.something
与输入绑定的方式,以及对v-model
指令的一些混淆之处。
回顾一下,v-model
指令是一种设置组件上属性并监听更新值事件的简写方式。
在Vue 2中,它是:
<child-component
:value="myValue"
@input="(nevValue) => myValue = newValue"
/>
它等同于
<child-component v-model="myValue"/>
它允许父级和子级都可以更改变量("双向绑定")。请注意,属性名称和事件与HTML输入元素的属性名称和事件匹配("value"属性和"input"事件),可能是因为它代表了最熟悉的情况,其中一个值绑定到输入:
<input type="text" v-model="myText"/>
然而,为了允许在组件上进行多个双向绑定,Vue 2还引入了第二种方式,允许绑定到子组件的任何属性,而不仅仅是"value"。这就是.sync
修饰符:
<child-component :childComponentProp.sync="myVar"/>
它等同于:
<child-component
:childComponentProp="myVar"
@update:childComponentProp="(newValue) => myVar = newValue"
/>
在Vue 3中,他们决定统一这两种方式,去掉.sync
,而是允许将属性名称传递给v-model
,类似于将插槽名称传递给v-slot
指令,即v-model:childComponentProp="myVar"
,与v-slot
一样,v-model
独自等同于v-model:modelValue
。所以它等同于:
<my-component
:modelValue="myValue"
@update:modelValue="(nevValue) => myValue = newValue"
/>
但上述方式仅适用于Vue组件。在HTML输入元素上使用v-model
时,它仍然与Vue 2中的行为相同,绑定到"value"属性和"input"事件。它仍然等同于:
<input :value="myValue" @input="(nevValue) => myValue = nevValue"/>
然而,这种行为是普通v-model
(即不带属性名称的情况)的特例。我认为这就是混淆的根源。
当明确使用v-model:value
时,它会绑定到@update:value
事件,也就是说:
<input v-model:value="innerItem.something" type="text">
等同于:
<input type="text"
:value="innerItem.something"
@update:value="(newValue) => innerItem.something = newValue"
/>
但是普通HTML元素不会发送该事件。
长话短说,当绑定到本地输入元素时,您必须使用v-model=
而不是v-model:value=
。这样有意义吗?希望有所帮助。
英文:
So, as we figured out, the problem came from the way innerItem.something
was bound to the input, and some confusion around the v-model
directive.
As a recap, the v-model
directive is short-hand for setting a prop on a component and listening to an event which updates the value.
In Vue 2, that was:
<child-component
:value="myValue"
@input="(nevValue) => myValue = newValue"
/>
which is equivalent to
<child-component v-model="myValue"/>
and it allows a variable to be changed by parent as well as child ("two-way binding"). Note that property name and event matches that of a HTML input element (the "value" attribute and the "input" event), probably because it represents the most familiar case, where a value is bound to an input:
<input type="text" v-model="myText"/>
However, to allow for multiple two-way bindings on a component, Vue 2 also introduced a second way, which allows to bind to any of the child components props, not just "value". This is the .sync
modifier:
<child-component :childComponentProp.sync="myVar"/>
which is equivalent to:
<child-component
:childComponentProp="myVar"
@update:childComponentProp="(newValue) => myVar = newValue"
/>
In Vue 3, they decided to unify the two, dropping .sync
and instead allowing to pass a prop name to v-model
similar to how slot names are passed to the v-slot
directive, i.e. v-model:childComponentProp="myVar"
, and similar as v-slot
alone is equivalent to v-slot:default
, v-model
alone is equivalent to v-model:modelValue
. So it is equivalent to:
<my-component
:modelValue="myValue"
@update:modelValue="(nevValue) => myValue = newValue"
/>
But the above only applies for Vue components. When using v-model
on an HTML input element, it sill behaves like in Vue 2 and binds to the "value" attribute and the "input" event. It is still equivalent to:
<input :value="myValue" @input="(nevValue) => myValue = nevValue"/>
However, that behavior is a special case of plain v-model
(i.e. without a prop name). And I think this is where the confusion comes from.
Using v-model:value
explicitly binds to the @update:value
event, i.e. this
<input v-model:value="innerItem.something" type="text">
is equivalent to:
<input type="text"
:value="innerItem.something"
@update:value="(newValue) => innerItem.something = newValue"
/>
but that event is not sent by a plain HTML element.
So long long story short, you have to use v-model=
instead of v-model:value=
when binding to a native input element.
Does that make sense? Hope it helps.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论