首页 > 解决方案 > v-for 似乎改变了数组顺序

问题描述

数据对象:

{
    "headers": {
        "location": "Location",
        "postcode": "Postcode",
        "contributors": "Contributors",
        "contributions": "Contributions",
        "percentage": "Percentage"
    },
    "rows": [
        {
            "postcode": "3018",
            "contributors": 2,
            "contributions": 2,
            "location": "Seaholme",
            "percentage": 67
        },
        {
            "postcode": "3013",
            "contributors": 1,
            "contributions": 1,
            "location": "Yarraville West",
            "percentage": 33
        }
    ]
}

模板:

<thead>
<tr>
    <th v-for="(v, k) in data.result.headers" :key="k">
    {{ v }}
    </th>
</tr>
</thead>
<tbody>
<tr v-for="(row, i) in data.result.rows" :key="i">
    <td :key="j" v-for="(col, j) in row">
        {{ col }}
    </td>
</tr>
</tbody>

输出: 在此处输入图像描述

所以表头和表体是两个独立的对象。虽然标题似乎遵​​循顺序,但行对象却没有。如何确保它们始终正确对齐?

标签: javascriptvue.jsvuejs3v-for

解决方案


您可以创建computed. rows这将是相同的列表,但按键keys的顺序排列。header这是一个可能的解决方案:

new Vue({
  el: "#app",
  data: () => ({
    "headers": { "location": "Location", "postcode": "Postcode", "contributors": "Contributors", "contributions": "Contributions", "percentage": "Percentage" },
    "rows": [
      { "postcode": "3018", "contributors": 2, "contributions": 2, "location": "Seaholme", "percentage": 67 },
      { "postcode": "3013", "contributors": 1, "contributions": 1, "location": "Yarraville West", "percentage": 33 }
    ]
  }),
  computed: {
    orderedRows() {
      const headers = Object.keys(this.headers);
      return this.rows.map(row => 
        headers.reduce((orderedRow, key) => 
          ({ ...orderedRow, [key]: row[key] })
        , {})
      );
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <table>
    <thead>
      <tr>
        <th v-for="(v, k) in headers" :key="k">{{ v }}</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(row, i) in orderedRows" :key="i">
        <td v-for="(col, j) in row" :key="j">{{ col }}</td>
      </tr>
    </tbody>
  </table>
</div>

受@CertainPerformance 评论启发的另一种可能方式:

new Vue({
  el: "#app",
  data: () => ({
    "headers": { "location": "Location", "postcode": "Postcode", "contributors": "Contributors", "contributions": "Contributions", "percentage": "Percentage" },
    "rows": [
      { "postcode": "3018", "contributors": 2, "contributions": 2, "location": "Seaholme", "percentage": 67 },
      { "postcode": "3013", "contributors": 1, "contributions": 1, "location": "Yarraville West", "percentage": 33 }
    ]
  }),
  computed: {
    headerKeys() {
      return Object.keys(this.headers);
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <table>
    <thead>
      <tr>
        <th v-for="(v, k) in headers" :key="k">{{ v }}</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(row, i) in rows" :key="i">
        <td v-for="(header, j) in headerKeys" :key="j">{{ row[header] }}</td>
      </tr>
    </tbody>
  </table>
</div>


推荐阅读