1ページで送信する大きなフォームがあります。
<container>
<formA>
<formB>
<formC>
<submitButton>
<container>
どうやらこんな感じです。そして私はすべてのフォームデータを保存するストアを持っています。次に、ユーザーが送信ボタンをクリックすると、vuexストアを使用してすべてのフォームデータを収集します。
問題は、ストア内のフォームデータを毎回更新する必要があることです。
だから私はvueコンポーネントでこのようになります
watch: {
userInput (val) {
this.updateState(val)
}
フォームデータ(v-modelとバインド)を監視して、入力が変更されたときに状態を更新します。
または、vuexdocに記載されているこのようなものです。
userInput: {
get () {
return this.$store.state.userInput
},
set (val) {
this.updateState(val)
}
}
まあ..これらは良い考えではないと思います。 vuexでフォーム処理を行うためのより良い方法はありますか?
Vuexでのフォーム処理を非常に簡単にする小さなツールを作成しました: vuex-map-fields
import Vue from 'vue';
import Vuex from 'vuex';
// Import the `getField` getter and the `updateField`
// mutation function from the `vuex-map-fields` module.
import { getField, updateField } from 'vuex-map-fields';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
fieldA: '',
fieldB: '',
},
getters: {
// Add the `getField` getter to the
// `getters` of your Vuex store instance.
getField,
},
mutations: {
// Add the `updateField` mutation to the
// `mutations` of your Vuex store instance.
updateField,
},
});
<template>
<div id="app">
<input v-model="fieldA">
<input v-model="fieldB">
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields';
export default {
computed: {
// The `mapFields` function takes an array of
// field names and generates corresponding
// computed properties with getter and setter
// functions for accessing the Vuex store.
...mapFields([
'fieldA',
'fieldB',
]),
},
};
</script>
Vuex-map-fieldsの詳細については、私のブログをご覧ください: Vue、Vuex、およびvuex-map-fieldsを使用して複数行のフォームを処理する方法
これにはディープウォッチャーを使用し、オブジェクトにすべてのフィールドを含めます。データの保存、Object.keysを反復処理して各フィールドをその変数名とともにフォームオブジェクトに格納する、またはフォーム全体を格納するために、複数のアプローチを使用できます。あなたが必要かもしれません。
v-model.lazy="form.myfield"
を使用して、ユーザーがフィールドを離れたときにのみバインディングを更新することを示すこともできます。
<template>
<div>
<!-- You can optionally use v-model.lazy="form.field1" to only update once user has exited the field or pressed enter -->
<input v-model="form.field1" />
<input v-model.lazy="form.field2" />
</div>
</template>
<script>
export default {
props: ['value'],
data: function () {
return {
internalForm: {
field1: null,
field2: null
}
}
},
watch: {
internalForm: {
handler: function (newValue) {
// Emit new form object to parent component so we can use v-model there
this.$emit('input', this.form)
// Or save form data
this.handleFormSave(this.form)
},
// Tell vue to do a deep watch of entire form object to watch child items in the object
deep: true
}
}
}
</script>
<template>
<form-component v-model="forms.form1" />
<submit-button @click="saveAllFormData" />
</template>
<script>
export default {
data: function () {
return {
forms: {
form1: null // This will be updated when 'input' is emitted
}
}
},
watch: {
forms: {
handler: function (newValue) {
if (allFormsValid && readyToSave)
saveAllFormData(newValue);
},
deep: true
}
}
}
</script>
私はこの問題に関して頭痛がした。
Vuex docには、すべてのフィールドのストアを更新する必要があると記載されています。それは何のためにタイプするの戦利品ですか?
私たちは、機能する1つのソリューションを作成します。これは、ストアオブジェクトをローカルオブジェクトに複製することに基づいています。
//We are passing (vuexstore) 'item' object from parent component:
//<common-item v-bind:item="item" ....
props: ['item'],
// create localItem - this is reactive object for vuex form
data: () => {
return {
localItem: null
}
},
// make clone on created event
created: function() {
this.localItem = this._clone(this.item)
},
// watch vuexstore 'item' for changes
watch: {
item: function(val) {
this.localItem = this._clone(this.item)
}
},
// map mutations and update store on event
methods: {
...mapMutations([
'editItem'
]),
updateItemHandler: function() {
this.editItem({ item: this._clone(this.localItem) })
},
_clone: function(o){
return JSON.parse(JSON.stringify(o))
}
},
内部フォームの使用:
<input v-model="localItem.text" @keyup="updateItemHandler" type="text" class="form-control"></input>
これはvuexの欠如だけだと思います。はるかに短く、組み込みのソリューションがあるはずです。