【问题标题】:How to get rid of cloning / duplication of elements in vue?如何摆脱 vue 中元素的克隆/重复?
【发布时间】:2020-05-22 14:33:06
【问题描述】:

我是一名初级程序员,我创建了一个像 trello 这样的水疗中心。创建板。在板子创建列表中,它们以不同的 id 显示不同,但列表项以相同的 id 显示,并且它们在每个列表中重复。对不起我的英语:) 帮助我,请详细说明问题所在.. 非常感谢您

vuex 文件 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: {
  }
})

创建列表的页面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

【问题讨论】:

  • 你有 itemslistsboards - 但我不知道 item 如何“知道”它应该属于哪里(list 它在什么位置),并且lists 似乎不知道他们的boards。 (在另一个方向上也是如此 - boards 不知道他们有什么 listslists 不知道他们应该包含什么 items。但我可能错过了这个逻辑。)
  • @muka.gergely,你是绝对正确的.. 如果你创建一个新的板,那么所有的列表都在那里重复.. 请告诉我如何解决这个问题:让工作表了解哪个板属于,等等?
  • 好的,那么我准备一个答案,向您展示解决方案(可能需要一些时间,因为这里是工作日)

标签: javascript vue.js trello


【解决方案1】:

尝试遵循您布置的结构的基本理念。我补充说:

  • id 到所有项目,以便他们可以被识别
  • children 到适当的项目,这样你就可以跟踪其中的内容

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>

使用此设置,您可以非常轻松地更改层次结构:只需从一个Array 的孩子中删除一个 ID 并将其添加到另一个(例如,从 table ID 1 的 children 数组中删除 '1.1' 并将其添加到table ID 2 的 children 数组 - 将所有内容移至 table ID 2。tryMovingList() 正是这样做的 - 此方法/操作并非万无一失,仅供您尝试移动一个整体列表)

可能有其他模式可以解决这个问题(例如真正的 链表 数据结构或 mediator 模式),但对于较小的应用程序,我认为这是可以的(我会用它... :))。

一条建议

如果您想在突变时将状态存储在localStorage 中,请不要自己动手 - 使用 Vuex 的集成 subscribe 机制:https://vuex.vuejs.org/api/#subscribe

【讨论】:

  • 非常感谢您..我想成为像您这样的专业人士,再次感谢您
  • @sergius 非常感谢您的夸奖! :) 但请相信我 - 时间会带来经验(然后你会发现总有人比你有更多的知识,所以学习永远不会停止 :D)无论如何,我很高兴我能提供帮助!
  • 请帮我更多的时间。不同的表格显示在不同的表中,但是渲染器发誓,它显示错误“渲染中的错误:”TypeError:_vm.list未定义“”虽然在vuex中通过console.log(list.children)访问时,显示列表的所有子项。我们可以通过 Skype 或任何信使联系吗?
  • @sergius 可能是这些项目的启动顺序有问题。请使用您所做的代码创建一个 JSFiddle(或类似的东西)。
  • github.com/audito/copyTrello那里方便吗?组件“CreateList”中的错误
猜你喜欢
  • 1970-01-01
  • 2013-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-27
相关资源
最近更新 更多