var store = new Vuex.Store({ state: { list: [ { id: 'fruits', name: '果物', items: [ { id: 1, name: 'りんご', price: 100 }, { id: 2, name: 'ばなな', price: 200 }, { id: 3, name: 'いちご', price: 300 }, ] }, { id: 'vegetables', name: '野菜', items: [ { id: 1, name: 'とまと', price: 10 }, { id: 2, name: 'きゅうり', price: 20 }, ] } ], editid: null, }, mutations: { setEditId (state, id) { state.editid = id }, updateItems (state, catdata) { var idx = _.findIndex(state.list, function(o) { return o.id == catdata.id }) if (idx != -1) { state.list[idx].items = _.cloneDeep(catdata.items) } }, }, getters: { currentEditCat: state => { return state.list[state.editid] } } }) // エディターアイテム var cmpEditorItem = Vue.extend({ template: '#cmp-editor-item', props: { 'item': Object }, data: function() { return { intarnalItem: null } }, watch: { item: { handler: function () { this.intarnalItem = _.cloneDeep(this.item) }, immediate: true }, }, methods: { update: function() { this.$emit('update', this.intarnalItem) } }, }) // エディター var cmpEditor = Vue.extend({ template: '#cmp-editor', data: function() { return { intarnalCat: null, } }, computed: Vuex.mapState([ 'editid' ]), watch: { editid: { handler: function () { this.intarnalCat = _.cloneDeep(store.getters.currentEditCat) }, immediate: true } }, methods: { updateItem: function(idx, item) { this.$set(this.intarnalCat.items, idx, item) }, cancel: function() { store.commit('setEditId', null) }, }, components: { 'cmp-editor-item': cmpEditorItem }, }) // カテゴリ一覧 var cmpList = Vue.extend({ template: '#cmp-list', props: { 'cat': Object, 'catidx': Number }, methods: Vuex.mapMutations({'edit':'setEditId'}) }) // ルート var app = new Vue({ el: '#app', store, computed: Vuex.mapState([ 'list', 'editid' ]), methods: Vuex.mapMutations(['updateItems']), components: { 'cmp-list': cmpList, 'cmp-editor': cmpEditor }, })
<!-- app --> <div id="app"> <div class="rows"> <section> <div class="cmpname">cmp-list</div> <ul> <cmp-list v-for="(cat, idx) in list" :cat="cat" :catidx="idx" :key="cat.id"></cmp-list> </ul> <cmp-editor @update="updateItems" v-if="editid!=null"></cmp-editor> </section> <section> <pre>{{ list }}</pre> </section> </div> </div> <!-- cmp-list テンプレート --> <script type="text/x-template" id="cmp-list"> <li> カテゴリ: {{ cat.name }} <button @click="edit(catidx)">編集</button> <ul> <li v-for="(itemi, idx) in cat.items" :key="itemi.id">{{ itemi.name }} {{ itemi.price }} 円</li> </ul> </li> </script> <!-- cmp-editor テンプレート --> <script type="text/x-template" id="cmp-editor"> <div class="cmp-editor"> <div class="cmpname">cmp-editor</div> <form @submit.prevent="$emit('update', intarnalCat)"> <div>編集: {{ intarnalCat.name }}</div> <ul> <li v-for="item in intarnalCat.items">{{ item.name }} / {{ item.price }}</li> </ul> <ul> <cmp-editor-item v-for="(item, idx) in intarnalCat.items" :item="item" :key='item.id' @update="updateItem(idx, $event)"></cmp-editor-item> </ul> <button>決定</button> <button type="button" @click="cancel">キャンセル</button> </form> </div> </script> <!-- cmp-editor-item テンプレート --> <script type="text/x-template" id="cmp-editor-item"> <li> <div class="cmpname">cmp-editor-item</div> 名前 <input type="text" size="10" v-model.lazy="intarnalItem.name" @change="update"> 価格 <input type="text" size="3" v-model.number.lazy="intarnalItem.price" @change="update"> </li> </script>