简体   繁体   中英

How to get rid of cloning / duplication of elements in vue?

I'm a beginner programmer and I create a spa like trello. Creates boards. In the board creates lists, they are displayed different with different id, but the list items are displayed with the same id and they are duplicated in each list. Sorry for my english:) Help me, please and tell in detail what the problem is.. Thank you very much

vuex file router.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    boards: JSON.parse(localStorage.getItem('boards') || '[]'),
    lists: [],
    items: []
    // items: JSON.parse(localStorage.getItem('items') || '[]')
    // lists: JSON.parse(localStorage.getItem('lists') || '[]')
  },
  mutations: {
    addBoard(state, board) {
      state.boards.push(board)
      localStorage.setItem('boards', JSON.stringify(state.boards))
    },
    addList(state, list) {
      state.lists.push(list)
      // localStorage.setItem('lists', JSON.stringify(state.lists))
    },
    createItemListt(state, item) {
      state.items.push(item)
      // localStorage.setItem('items', JSON.stringify(state.items))
    }
  },
  actions: {
    addBoard({commit}, board) {
      commit('addBoard', board)
    },
    addList({commit}, list) {
      commit('addList', list)
    },
    createItemListt({commit}, item) {
      commit('createItemListt', item)
    }
  },
  getters: {
    boards: s => s.boards,
    taskById: s => id => s.boards.find(t => t.id === id),
    lists: d => d.lists,
    items: a => a.items
  },
  modules: {
  }
})

the page on which the lists are created MyBoard.vue

<template>
  <div>
    <div class="wrapper">
      <div class="row">
        <h1>{{board.title}}</h1>
        <div class="list " v-for="list in lists" :key="list.idList">
          <div class="list__title">
            <h3>{{list.titleList}}</h3>
          </div>
          <div class="list__card" v-for="item in items" :key="item.idItemList">
            <span class="list__item">{{item.itemList}}</span>
            <a class="btn-floating btn-tiny btn-check" tag="button">
              <i class="material-icons">check</i>
            </a>
          </div>
            <createItemList />
        </div>
         <createList />
      </div>

    </div>
  </div>
</template>

<script>
export default {
  computed: {
    board() {
      return this.$store.getters.taskById(+this.$route.params.id);
    },
    lists() {
      return this.$store.getters.lists;
    },
    items() {
      return this.$store.getters.items;
    }
  },

  components: {
    createList: () => import("../components/createList"),
    createItemList: () => import("../components/createItemList")
  }
};
</script>

CreateList.Vue

<template>
  <div>
    <div class="row">
      <div class="new-list" v-show="isCreating">
        <div class="list__title input-field">
          <input
            type="text"
            required
            id="list-title"
            class="none validate"
            tag="button"
            autofocus
            v-model="titleList"
            v-on:keyup.enter="createList"
          />
          <label for="list-title">Enter Title List</label>
        </div>

        <a class="btn-floating transparent btn-close" tag="button" @click="closeList">
          <i class="material-icons">close</i>
        </a>
      </div>
      <div class="create-list z-depth-2" v-show="!isCreating">
        <p>Create list</p>
        <a
          class="btn-floating btn-large waves-effect waves-light deep-purple lighten-2 pulse"
          tag="button"
          @click="addList"
          v-on:keyup.enter="addList"
        >
          <i class="material-icons">add</i>
        </a>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data: () => ({
    isCreating: false,
    titleList: "",
    idList: ""
  }),
  methods: {
    addList() {
      this.isCreating = true;
    },
    closeList() {
      this.isCreating = false;
    },
    createList() {
      if (this.titleList == "") {
        return false;
      }
      const list = {
        idList: Date.now(),
        titleList: this.titleList
      };
      this.$store.dispatch("addList", list);
      this.titleList =  "";
      this.isCreating = false;
      console.log(list.titleList);
    }
  }
};
</script>

CreateItemList.vue

<template>
  <div>
    <div class="add-item">
      <div class="textarea-item input-field" v-show="isAdding">
        <input
          type="text"
          class="validate"
          id="list-item"
          v-model="itemList"
          v-on:keyup.enter="createItemList"
          autofocus
        />
        <label for="list-item">Enter Item List</label>
      </div>
      <a class="waves-effect waves-light btn" v-show="!isAdding" @click="addCard">
        <i class="material-icons right">add</i>Add Card
      </a>
    </div>
  </div>
</template>

<script>
export default {
  data: () => ({
    isAdding: false,
    itemList: "",
  }),
  methods: {
    addCard() {
      this.isAdding = true;
    },
    createItemList() {
       if (this.itemList == "") {
        return false;
      }
      const item = {
        idItemList: Date.now(),
        itemList: this.itemList
      };

      this.$store.dispatch("createItemListt", item);
      this.itemList = "";
      this.isAdding = false;
    }
  }
};
</script>

attach photo

Tried to go with the basic idea of the structure you laid out. I added:

  • id to all items, so they can be identifed
  • children to appropriate items, so you can keep track of what's in them

 const store = new Vuex.Store({ state: { tables: [ { id: 1, children: ['1.1', '1.2'] }, { id: 2, children: ['2.1'] } ], lists: [ { id: '1.1', children: ['1.1.1'] }, { id: '1.2', children: ['1.2.1'] }, { id: '2.1', children: ['2.1.1', '2.1.2'] }, ], cards: [ { id: '1.1.1' }, { id: '1.2.1' }, { id: '2.1.1' }, { id: '2.1.2' }, ] }, mutations: { ADD_CARD(state, listId) { const list = state.lists.find(e => e.id === listId) const cards = state.cards const card = { id: Date.now() } cards.push( card ) list.children.push( card.id ) }, ADD_LIST(state, tableId) { const table = state.tables.find(e => e.id === tableId) const lists = state.lists const list = { id: Date.now(), children: [] } lists.push( list ) table.children.push( list.id ) }, ADD_TABLE(state) { const tables = state.tables const table = { id: Date.now(), children: [] } tables.push( table ) }, TRY_MOVING_LIST(state) { const table1 = state.tables.find(e => e.id === 1) const table2 = state.tables.find(e => e.id === 2) const item = table1.children.pop() // remove the last item table2.children.push(item) } }, actions: { addCard({ commit }, listId) { commit('ADD_CARD', listId) }, addList({ commit }, tableId) { commit('ADD_LIST', tableId) }, addTable({ commit }) { commit('ADD_TABLE') }, tryMovingList({ commit }) { commit('TRY_MOVING_LIST') } }, getters: { getTables: s => s.tables, getListById: s => id => s.lists.find(e => e.id === id), getCardById: s => id => s.cards.find(e => e.id === id), } }) Vue.component('CustomCard', { props: ['card'], template: `<div> card ID: {{ card.id }}<br /> </div>` }) Vue.component('CustomList', { props: ['list'], template: `<div> list ID: {{ list.id }}<br /> <custom-card v-for="item in list.children":key="item":card="getCard(item)" /> <button @click="addCard">ADD CARD +</button> <hr /> </div>`, methods: { getCard(id) { return this.$store.getters.getCardById(id) }, addCard() { this.$store.dispatch('addCard', this.list.id) } } }) Vue.component('CustomTable', { props: ['cTable'], template: `<div> table ID: {{ cTable.id }}<br /> <custom-list v-for="item in cTable.children":key="item":list="getList(item)" /> <button @click="addList">ADD LIST +</button> <hr /> </div>`, methods: { getList(id) { return this.$store.getters.getListById(id) }, addList(id) { this.$store.dispatch('addList', this.cTable.id) } } }) new Vue({ el: "#app", store, computed: { tables() { return this.$store.state.tables } }, methods: { addTable() { this.$store.dispatch('addTable') }, tryMovingList() { // this function will move the last list in table ID 1 // to the end of table ID 2's lists // NOT FOOLPROOF - you should add error handling logic. this.$store.dispatch('tryMovingList') } } })
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <script src="https://unpkg.com/vuex"></script> <div id="app"> <button @click="tryMovingList()">MOVE LIST</button><br /> <button @click="addTable()">ADD TABLE +</button> <hr /> <custom-table v-for="item in tables":key="'table-' + item.id":c-table="item" /> </div>

With this setup you can change the hierarchy quite easily: just delete an ID from one Array of children and add it to another (eg remove '1.1' from table ID 1's children array and add it to table ID 2's children array - everything moved to table ID 2. tryMovingList() does exactly this - this method/action is not foolproof , just for you to try out moving a whole list)

There could be other patterns to solve this problem (like a real linked list data structure or the mediator pattern), but for smaller apps this is OK, I think (I would use it... :) ).

ONE PIECE OF ADVICE

If you want to store state in localStorage on mutations, don't do it by yourself - use Vuex 's integrated subscribe mechanism: https://vuex.vuejs.org/api/#subscribe

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM