【问题标题】:Vue.js subtotal on list using v-if statementVue.js 使用 v-if 语句对列表进行小计
【发布时间】:2018-01-24 23:48:41
【问题描述】:

我想知道如何计算 vue.js 列表的总数。 我的情况有点复杂,所以请允许我举个例子。 假设我正在渲染一张发票项目表。这是我的代码:

<table>
<template v-for="(invoice_item, index) in invoice_items" v-if="invoice_item.category === 'widgets'">
    <tr>
        <td>@{{ invoice_item.name }}</td>
        <td><input type="number" class="inline-edit" v-model="invoice_item.rate"></td>
        <td><input type="number" class="inline-edit" v-model="invoice_item.quantity"></td>
        <td><input type="number" class="inline-edit" v-model="invoice_item.activation_fee"></td>
        <td class="subtotal">@{{ computeSubTotal(invoice_item) }}</td>
    </tr>
</template>
</table>

对于每一行,我计算了一个小计并将其显示在最后一列中。这是我的 vue.js javascript 中的代码:

computeSubTotal: function(invoice_item) {
    return(this.formatPrice((parseFloat(invoice_item.rate) * parseFloat(invoice_item.quantity) + parseFloat(invoice_item.activation_fee))));
},

这很好用。但是,现在我想显示所有小计的总计。换句话说:

我该如何解决这个问题?

谢谢!

【问题讨论】:

标签: javascript vue.js vuejs2


【解决方案1】:

使用计算属性进行计算。

console.clear()

new Vue({
  el: "#app",
  data: {
    invoice_items: [
      {
        name: "Community / Support",
        rate: 5.20,
        quantity: 1,
        activation_fee: 3.00,
        category: "widgets"
      },
      {
        name: "Infrastructure",
        rate: 269.00,
        quantity: 3,
        activation_fee: 1.00,
        category: "widgets"
      },
      {
        name: "Infrastructure",
        rate: 269.00,
        quantity: 3,
        activation_fee: 1.00,
        category: "stuff"
      },
    ]
  },
  computed: {
    // probably need a better name for this, but its just an example
    itemsWithSubTotal() {
      return this.invoice_items.map(item => ({
          item,
          subtotal: this.computeSubTotal(item)
      }))
    },
    // calculate the total of all the subtotalItems grouped by category
    totalByCategory() {
      // group the items by category
      let grouped = this.itemsWithSubTotal
        .reduce((acc, val) => {
          // This line does everything the lines below do, but in a very
          // terse, possibly confusing way.
          //(acc[val.item.category] = acc[val.item.category] || []).push(val)
          
          //if there is not already an array set up for the current
          //category, add one
          if (!acc[val.item.category]) 
            acc[val.item.category] = []
          // push the current value into the collection of values
          // for this category
          acc[val.item.category].push(val)
          // return the accumulator (object)
          return acc
        }, {})
        
      // create an object that has the total for each category
      return Object.keys(grouped).reduce((acc, val) => {
        acc[val] = grouped[val].reduce((total, item) => total += item.subtotal, 0)
        return acc
      }, {})
    }
  },
  methods: {
    computeSubTotal: function(invoice_item) {
      //formatPrice is removed here because its not defined in the question
      return ((parseFloat(invoice_item.rate) * parseFloat(invoice_item.quantity) + parseFloat(invoice_item.activation_fee)));
    },
  }
})
input {
  width: 5em
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <table>
    <template v-for="(invoice_item, index) in itemsWithSubTotal" v-if="invoice_item.item.category === 'widgets'">
    <tr>
        <td>{{ invoice_item.name }}</td>
        <td><input type="number" class="inline-edit" v-model="invoice_item.item.rate"></td>
        <td><input type="number" class="inline-edit" v-model="invoice_item.item.quantity"></td>
        <td><input type="number" class="inline-edit" v-model="invoice_item.item.activation_fee"></td>
        <td class="subtotal">{{ invoice_item.subtotal }}</td>
    </tr>
</template>
  </table>
  Total: {{totalByCategory["widgets"]}}
</div>

itemsWithSubTotal 可能看起来有点奇怪。

itemsWithSubTotal() {
  return this.invoice_items.map(item => ({
      item,
      subtotal: this.computeSubTotal(item)
  }))
},

基本上,这会返回一个具有一个属性的新对象,item 指向原始项目和一个小计属性。我这样做是为了让v-model 在模板中工作并自动更新计算的属性。

【讨论】:

  • 很好的答案!仍然试图理解这一切。 acc[val.item.category] ​​= acc[val.item.category] ​​是做什么的?
  • @clone45 (acc[val.item.category] = acc[val.item.category] || []).push(val) 这行有点棘手,我可能会写得更清楚。我在那个 reducer 中所做的是创建一个看起来像这样的对象:{widgets: [...], stuff: [...]}。换句话说,按类别对对象进行分组。 acc[val.item.category] = acc[val.item.category] || [] 将当前类别设置为自身或空数组(如果尚不存在)。该表达式将计算出 acc[val.item.category] 的最终结果,这意味着我们可以将最新值推送到分组中。
  • 非常棒的代码。我不得不做一些小的调整。我的 computeSubTotal() 函数使用了一个名为 formatPrice 的辅助函数,它在小计中添加了美元符号和逗号。这导致 total += item.subtotal 进行字符串连接而不是加法。修复后,代码运行良好。
猜你喜欢
  • 2018-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
相关资源
最近更新 更多