问题
I've got a list of components where I'd like them all to be editable / replicate state to the parent component.
The list component exists as:
Vue.component("shortcuts", {
props: {
shortcuts: Array
},
template: '...<shortcut-entry v-for="(shortcut, index) in shortcuts" v-bind:key="index" v-bind="shortcut" @remove="remove(index)"></shortcut-entry>...'
})
It's used with a model like this:
<shortcuts v-bind:shortcuts.sync="shortcuts"></shortcuts>
Now each shortcut-entry
component will contain lots of values which I would like to be propagated back to the top level list of objects:
Vue.component("shortcut-entry", {
props: {
mod_ctrl: Boolean,
mod_alt: Boolean,
mod_shift: Boolean,
keypress: String,
action: String,
...
},
Each of those properties exists as a separate checkbox / input on the page with (for example) <input ... v-model="action">
. The way I understand it, I could wire the update events back to the parent component and do replacements there... but that sounds like a lot of boilerplate code.
Can I somehow propagate any modifications for those props back to the parent component automatically? (avoiding the "Avoid mutating a prop directly" warning)
It seems to work as I expect if I move every prop I currently have into another level (so I have props: {options: Object}
, v-bind it with .sync
and assign everything there), but I'm looking into some more explicit solution which actually declares the relevant options ahead of time.
回答1:
You can use sync
modifier with the props object notation together. Instead of v-bind="shortcut"
use v-bind.sync="shortcut"
This way shortcut
component can declare all props (instead of just options
object) and still be able to notify parent about mutation
But you need to change how you bind your inputs. Instead of <input ... v-model="action">
you need to <input ... v-bind:value="action" v-on:input="$emit('update:action', $event.target.value)">
. Problem with this is that different <input>
types use different names for value and change event
To work around it and keep using v-model
you can declare computed
for each prop and use v-model="actionComputed"
computed: {
actionComputed: {
get: function() { return this.action },
set: function(value) { this.$emit('update:action', value) }
}
}
So the result is again lot of boilerplate...
TL:DR
If you want all props declared ahead of time (instead of single prop of type object
), some boilerplate is necessary. It can be reduced by generating computed
props for v-model
on the fly (same way Vuex helpers generate computed
to access and update Vuex state) but I don't think it is worth the effort. Just pass an object and let the <input>
components mutate it's properties...
来源:https://stackoverflow.com/questions/65503140/dealing-with-many-attributes-mapping-to-a-parent-component-list-in-vuejs