VueJS不会从组件重新呈现列表

时间:2019-07-30 16:16:29

标签: javascript vue.js vuex

尝试通过“ v-for”从vuex渲染数组。

“玩家卡”组件未呈现。 但是“ td”解决方案可以正常工作。

我在JSFiddle上的示例

HTML:

    <div id="app">
      <button v-on:click="moveItem">
        Move Item
      </button>

      <table cellspacing="2" border="1" cellpadding="5">
        <tr>
          <td v-for="(item, item_idx) in getItems" v-bind:key="item.col">{{ (item.card)? item.card.name : 'none' }}</td>
        </tr>
        <tr>
          <player-card v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></player-card>
        </tr>
      </table>
      <br/>
      <p>{{msg}}</p>
    </div>

商店:

    const store = new Vuex.Store({
      state: {
        items: [{ col: 0, row: 0 },
                { col: 1, row: 0 },
                { col: 2, row: 0, card: { name: "hello" } } ]
      },
      getters: {
        getterItems: state => { return state.items; }
      },

      mutations: {
        MOVE_ITEM: state => {
          state.items[0].card = state.items[2].card;
          delete state.items[2].card;
          state.message = JSON.stringify(state.items);
        }
      }

    });

组件:

    Vue.component('player-card', {
      props: {
        item: {
          type: Object,
          required: true
        }
      },
      template: '<td>{{ (item.card)? item.card.name : "none" }}</td>'
    });

应用程序:

    new Vue({
      el: '#app',
      store,
      data: function() {
        return {
          msg: ''
        }
      },
      computed: {
        getItems() { return this.$store.getters.getterItems; }
      },
      mounted: function() { 
        this.msg = JSON.stringify(this.getItems); 
      },
      methods: {
        moveItem() {
          this.$store.commit('MOVE_ITEM');
          this.msg = JSON.stringify(this.getItems);
        }
      }
    });

我已经尝试了许多解决方案,但是还没有找到简单的解决方案。也许有人会提供不同的架构解决方案。

3 个答案:

答案 0 :(得分:2)

您只需要更改此行:

<player-card v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></player-card>

对此:

<td is="player-card" v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></td>

这是必需的,因为您的模板是在DOM中指定的。浏览器将在Vue到达模板标记附近之前解析模板标记。 HTML解析规则仅允许某些元素成为<tr>的直接子代。其他任何元素将从<table>中拉出。到Vue解析模板时,<player-card>元素将已经移至<table>之外。

如果您使用其他一种技术来指定模板,则不会有问题。

解决方法是使用is属性指定组件而不是标签名称。

这在这里的文档中进行了解释:

https://vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats

答案 1 :(得分:1)

您需要使用特殊的is属性来绕过强加的元素结构,其中<tr>期望<td>是子元素,但会得到<player-card>(预先转换)。此外,您对阵列进行变异的方式还会引起反应性问题。考虑我的变化。

const store = new Vuex.Store({
  state: {
    items: [{
        col: 0,
        row: 0
      },
      {
        col: 1,
        row: 0
      },
      {
        col: 2,
        row: 0,
        card: {
          name: "hello"
        }
      }
    ]
  },
  getters: {
    getterItems: state => {
      return state.items;
    }
  },

  mutations: {
    MOVE_ITEM: state => {
      // Move the last element to the front
      state.items = [
        ...state.items.slice(-1),
        ...state.items.slice(0, -1)
      ];
      state.message = JSON.stringify(state.items);
    }
  }

});

Vue.component('player-card', {
  props: {
    item: {
      type: Object,
      required: true
    }
  },
  template: '<td>{{ (item.card)? item.card.name : "none" }}</td>'
});

new Vue({
  el: '#app',
  store,
  data: function() {
    return {
      msg: ''
    }
  },
  computed: {
    getItems() {
      return this.$store.getters.getterItems;
    }
  },
  mounted: function() {
    this.msg = JSON.stringify(this.getItems);
  },
  methods: {
    moveItem() {
      this.$store.commit('MOVE_ITEM');
      this.msg = JSON.stringify(this.getItems);
    }
  }
});
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>

<div id="app">
  <button v-on:click="moveItem">
        Move Item
      </button>

  <table cellspacing="2" border="1" cellpadding="5">
    <tr>
      <td v-for="(item, item_idx) in getItems" v-bind:key="item.col">{{ (item.card)? item.card.name : 'none' }}</td>
    </tr>
    <tr>
      <td is="player-card" v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></td>
    </tr>
  </table>
  <br/>
  <p>{{msg}}</p>
</div>

答案 2 :(得分:0)

我的问题也是在vuex中更新数组的问题。

有关此"Common Beginner Gotchas"

的信息
mutations: {
MOVE_ITEM: state => {
  // Move card
  state.items[0].card = state.items[2].card;
  delete state.items[2].card;

  // Simple deep array cloning
  state.items = JSON.parse(JSON.stringify(state.items));

  state.message = JSON.stringify(state.items);
}}

更新了JSFiddle

非常感谢大家。