Я оборачиваю голову вокруг этого, и я не могу понять, как это сделать.
Как я могу привязать входные данные к свойству объекта хранилища? Смысл: мой компонент знает только объект хранилища, но не знает заранее, какие свойства содержит объект.
Возьмите этот пример:
Vue.component('os-choice', {
template: `
<div>
<h5>Select OS</h5>
<div>
<label class = "checkbox">
<input type = "checkbox" value = "linux" v-model = "linux">
Linux
</label>
</div>
<div>
<label class = "checkbox">
<input type = "checkbox" value = "macos" v-model = "macos">
MacOS
</label>
</div>
<div>
<label class = "checkbox">
<input type = "checkbox" value = "windows" v-model = "windows">
Windows
</label>
</div>
</div>
`,
computed: {
linux: {
get() {
return store.state.linux;
},
set(val) {
store.commit('updateLinux', {
linux: val
});
}
},
macos: {
get() {
return store.state.macos;
},
set(val) {
store.commit('updateMacos', {
macos: val
});
}
},
windows: {
get() {
return store.state.windows;
},
set(val) {
store.commit('updateWindows', {
windows: val
});
}
},
}
});
Vue.component('os-choice2', {
template: `
<div>
<h5>Select OS</h5>
<div v-for = "(value,index) in os" :key = "index">
<label class = "checkbox">
<input type = "checkbox" value = "index" v-model = "value">
{{index}}
</label>
</div>
</div>
</div>
`,
computed: {
os: {
get(){ return store.state.os; },
set(event){
var name = event.target.value;
var value = event.target.checked;
store.commit('updateOs', {name: name, value: value});
}
},
}
});
const store = new Vuex.Store({
state: {
// initial state
linux: true,
macos: true,
windows: false,
os: {
linux: true,
macos: true,
windows: false,
}
},
mutations: {
updateLinux(state, payload) {
console.info('STORE: updated linux');
state.linux = payload.linux;
},
updateMacos(state, payload) {
console.info('STORE: updated MacOS');
state.macos = payload.macos;
},
updateWindows(state, payload) {
console.info('STORE: updated Windows');
state.windows = payload.windows;
},
updateOs(state, payload) {
console.info('STORE: updated OS');
state.os[payload.name] = payload.value;
}
}
});
var app = new Vue({
el: "#app",
})
.row{
width: 100%;
}
.column{
width: 50%;
}
<script src = "https://cdn.jsdelivr.net/npm/vue"></script>
<script src = "https://unpkg.com/[email protected]/dist/vuex.js"></script>
<div id = "app" style = "text-align:center;">
<div class = "row">
<div class = "column">
<os-choice></os-choice>
</div>
<div class = "column">
<os-choice2></os-choice2>
<div>
</div>
</div>
Первый компонент работает отлично. Второй компонент не обновляет хранилище: он генерирует ошибку «[vuex] Не изменять состояние хранилища vuex вне обработчиков мутаций».
Я думаю, что понимаю, почему это происходит: поскольку вычисляемое свойство компонента указывает на объект (а не на изменяемое свойство), v-model попытается изменить глубокое свойство, тем самым заставив изменить хранилище, которое вызовет ошибка еще до того, как компонент вызовет метод set() для объекта, верно?
Итак, что я хотел бы знать, так это то, как правильно это сделать?
Мой реальный сценарий заключается в том, что я создаю динамический фильтр с флажками, и во время выполнения я не знаю, сколько у него будет опций. Это означает, что я пройдусь по своим параметрам, чтобы создать флажки, но тогда привязка данных должна быть в форме «значения []». И тут начинаются мои головные боли.
Спасибо всем заранее
Из документации VueJs:
Custom events can also be used to create custom inputs that work with v-model. Remember that:
<input v-model = "searchText">
does the same thing as:
<input v-bind:value = "searchText" v-on:input = "searchText =
$event.target.value"
>
When used on a component, v-model instead does this:
<custom-input v-bind:value = "searchText" v-on:input = "searchText =
$event"
></custom-input>
Таким образом, вместо использования v-model
вы можете использовать value
в качестве v-bind:value = "value"
и отобразить событие для соответствующего обновления магазина, например: v-on:input = "store.commit('store.commit('updateOs', event.target.value)"
Другой компонент работает, поскольку вы следуете именно тому, что рекомендует делать Vuex: https://vuex.vuejs.org/guide/forms.html
Но на v-for
вы используете модель магазина напрямую.
Спасибо за ваш ответ @Reuel. Это ответ на мой вопрос. Я делал что-то подобное раньше, но у меня возникла проблема с начальными значениями, потому что они не загружаются во время выполнения, мне нужно ждать, пока значение будет готово. Но я, должно быть, делаю что-то не так, потому что я только что попробовал ваше предложение на своей кодовой ручке, и оно работает. Если хотите проверить: codepen.io/oscarcarvalho/pen/GaXgPg <os-choice3> теперь делает то, что мне нужно. Спасибо
Может быть много способов справиться с этим. Другое решение, которое я могу придумать, состоит в том, чтобы поддерживать модель привязки компонента вместо прямой привязки его к хранилищу и использовать
watch
для синхронизации с хранилищем.