首页 > 解决方案 > Vue 组件小计之和

问题描述

我需要在我的 Vue 应用程序中添加小计。

每个组件都有基于用户输入的自己的小计。然后需要将这些添加到组件之外的另一个输入中。

我一直被困在如何最好地引用组件之外的组件小计。这最好通过向#app 添加计算属性来完成吗?

<div id="app">
    <h1 style="padding: 2em 0 1em">Vue.JS Loop 2</h1>
    <div class="total">
        <input :value="form.income" @change="updateIncome" type="number" class="form-control" name="income" id="income" placeholder="Income">
        <!--Add all subtotals here-->
        <input :value="form.expenses" @change="updateExpenses" type="number" step="any" class="form-control" name="expenses" id="expenses" placeholder="Expenses">
        <hr/>
        <input v-model="form.dispIncome" type="number" step="any" class="form-control" name="dispIncome" id="dispIncome" placeholder="Disposable Income">
    </div>
    <div class="budget-container">
        <div class="budget" v-for="budget in budgets">
            {{budget}} Expenses
            <budget-line></budget-line>
        </div>
    </div>
</div>

<script>
    var budgetLine = Vue.extend({
        template: `
            <div>
                <p id="result"><strong>Total:</strong> $ {{ totalQty }} </p>
            <div class="row" v-for="item in items">
                <input type="text" placeholder="Item"></input>
                <input type="text" placeholder="How much?" v-model="item.qty"></input>
                <button @click="addItem">+</button>
                <button @click="removeItem">-</button>
            </div>
            </div>
        `,

        data: function() {
            return { items: [] };
        },

        computed: {
            totalQty() {
                return this.items.reduce((total, item) => {
                    return total + Number(item.qty);
                }, 0);
            },
        },

        methods: {
            addItem() {
                this.items.push({
                    qty: 0
                });
            }, 
            removeItem(item) {
                this.items.pop(item);
            }
        },

        mounted() {
            this.addItem()
        }
    });

    var budgetApp = new Vue({
        el: '#app',
        data: {
            budgets: ['One', 'Two', 'Three'], 
            form: {
                income: 0,
                expenses: 0,
                dispIncome: 0
            }
        }, 
        components: {
            'budget-line': budgetLine
        }, 
        methods: {
            updateIncome(event) {
                this.form.income = event.target.value
                this.form.dispIncome = this.form.income - this.form.expenses
            },
            updateExpenses(event) {
                this.form.expenses = event.target.value
                this.form.dispIncome = this.form.income - this.form.expenses
            }
        }
    });

</script>

标签: javascriptvue.js

解决方案


下面是修改后的代码,它将表单费用显示为您在每个预算部分下添加的多行费用总额:

添加了 watch 和 computed 的组合来实现这一点。以下是所做更改的高级摘要:

  • budgetLine组件中添加了一个观察者来发出更改totalQty
  • budgetApp组件中将预算数据修改为对象,将计算添加budgetKeys到渲染部分名称,添加calculateExpense将在从budgetLine 发出时调用的方法以更新预算和预算的观察者以更新form.expenses

var budgetLine = Vue.extend({
  template: `
            <div>
                <p id="result"><strong>Total:</strong> $ {{ totalQty }} </p>
            <div class="row" v-for="item in items">
                <input type="text" placeholder="Item"></input>
                <input type="text" placeholder="How much?" v-model="item.qty"></input>
                <button @click="addItem">+</button>
                <button @click="removeItem">-</button>
            </div>
            </div>
        `,

  data: function() {
    return {
      items: []
    };
  },
  watch: {
    totalQty(value) {
      this.$emit('update-expense', value)
    }
  },
  computed: {
    totalQty() {
      return this.items.reduce((total, item) => {
        return total + Number(item.qty);
      }, 0);
    },
  },

  methods: {
    addItem() {
      this.items.push({
        qty: 0
      });
    },
    removeItem(item) {
      this.items.pop(item);
    }
  },

  mounted() {
    this.addItem()
  }
});

var budgetApp = new Vue({
  el: '#app',
  data: {
    budgets: {
      'One': 0,
      'Two': 0,
      'Three': 0
    },
    form: {
      income: 0,
      expenses: 0,
      dispIncome: 0
    }
  },
  components: {
    'budget-line': budgetLine
  },
  watch: {
    budgets: {
      deep: true,
      handler() {
        this.form.expenses = this.budgetKeys.reduce((accum, key) => accum + this.budgets[key], 0)
      }
    }
  },
  computed: {
    budgetKeys() {
      return Object.keys(this.budgets)
    },
  },
  methods: {
    updateIncome(event) {
      this.form.income = event.target.value
      this.form.dispIncome = this.form.income - this.form.expenses
    },
    updateExpenses(event) {
      this.form.expenses = event.target.value
      this.form.dispIncome = this.form.income - this.form.expenses
    },
    calculateExpense(amount, budget) {
      this.budgets[budget] = amount;
      console.log(this.budgets)
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <h1 style="padding: 2em 0 1em">Vue.JS Loop 2</h1>
  <div class="total">
    <input :value="form.income" @change="updateIncome" type="number" class="form-control" name="income" id="income" placeholder="Income">
    <!--Add all subtotals here-->
    <input :value="form.expenses" @change="updateExpenses" type="number" step="any" class="form-control" name="expenses" id="expenses" placeholder="Expenses">
    <hr/>
    <input v-model="form.dispIncome" type="number" step="any" class="form-control" name="dispIncome" id="dispIncome" placeholder="Disposable Income">
  </div>
  <div class="budget-container">
    <div class="budget" v-for="budget in budgetKeys">
      {{budget}} Expenses
      <budget-line v-on:update-expense="calculateExpense($event, budget)"></budget-line>
    </div>
  </div>
</div>


推荐阅读