尝试从单个文件组件中的Vue组件中提取数据

时间:2018-09-12 13:35:42

标签: vue.js vuejs2 vue-component

这是我第一次尝试使用Vue.js,因此完全有可能我遗漏了一些非常明显的东西。

基本上,我有一个组件,可以计算一定数量的打印件所需的盒子数量(我从事印刷行业)。

如果需要的话,如果印刷件有多个部分,我有一个按钮可以创建一个附加组件。

我想以一种反应性的方式来更新所有零件所需的总盒数,但是我似乎无法达到目标。

以下是代码指向我的Gitlab存储库的链接:https://gitlab.com/dsross/printutils

任何帮助将不胜感激。

我还使用Browserify编写index.html中引用的build.js和build.css文件。

这是我的文件,以防万一没有人想要查看回购的情况:

App.vue

<template>
  <div id="app">
    <div>
    </div>
    <div>
      <calculator v-for="(part, index) in parts" :key="index"></calculator>
      <br />
      <br />
      <div class="card shadow-sm">
        <div class="card-body">
          <button type="button" class="btn" @click="addPart()">Add Part</button>
          <button type="button" class="btn" @click="totalBoxes">Total Boxes</button>
          <span>Box Total (all parts): </span><span id="grandtotal"></span>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  // import Hello from './components/Hello.vue'
  import Calculator from './components/Calculator.vue'

  export default {
    name: 'app',
    components: {
      Calculator
    },
    methods: {
      addPart: function () {
        console.log("Adding part");
        this.parts.push(Calculator);
      },
      totalBoxes: function () {
        console.log("totalBoxes called");
        let totalBoxes = 0;
        let partTotals = document.querySelectorAll("#partBoxTotal");
        for (var i = 0; i < partTotals.length; i++) {
          totalBoxes += parseInt(partTotals[i].innerHTML);
        }
        this.totalBoxCount = totalBoxes;
        document.getElementById("grandtotal").innerHTML = totalBoxes;
      }
    },
    data: function () {
      return {
        parts: [Calculator],
        totalBoxCount: 0
      }
    },
  }
</script>

Calculator.vue

<template>
    <div class="card shadow-sm" id="boxCalculator">
        <div class="card-body">
            <form>
                <div class="form-group">
                    <p>Paper:
                        <select class="custom-select" v-model="paperWeight">
                            <option v-for="(mweight, paper) in mweights" :key="mweight" v-bind:value="paper">{{paper}}</option>
                        </select>
                    </p>
                    <br />
                    <br />
                    <p>Final Width:
                        <input class="form-control" type="text" v-model="finalWidth" id="finalWidth" value="">
                    </p>
                    <p>Final Height:
                        <input type="text" class="form-control" v-model="finalHeight" id="finalHeight" value="">
                    </p>
                    <p>Sheets Per Unit:
                        <input type="text" class="form-control" v-model="numberOfSheets" id="numberOfSheets" name="numberOfSheets"
                            value="">
                    </p>
                    <p>Quantity:
                        <input type="text" class="form-control" v-model="quantity" id="quantity" name='quantity'>
                    </p>
                    <p>Stitched:
                        <input type="checkbox" v-model="stitched" name="stitched" id="stitched" value="">
                    </p>
                </div>
            </form>
            <div class="card">
                <div class="card-body">
                    <div id='results'>
                        <p id="partWeightTotal">Part Total Weight: {{ totalWeight }}</p>
                        <p><span>Part Box Total: </span><span id="partBoxTotal">{{ boxQuantity }}</span></p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    import {
        mWeights,
        stitchedMultiplier,
        maxArea
    } from "../constants.js"

    module.exports = {
        data: function () {
            return {
                paperWeight: this.selected,
                paperType: "",
                finalWidth: "",
                finalHeight: "",
                numberOfSheets: "",
                quantity: "",
                stitched: "",
                boxes: "",
                mweights: mWeights
            }
        },
        computed: {
            squareInches: function () {
                return this.finalHeight * this.finalWidth;
            },
            squareInchWeight: function () {
                let mWeight = mWeights[`${this.paperWeight}`];
                return (mWeight / 1000) / maxArea;
            },
            totalWeight: function () {
                return ((this.squareInches * this.squareInchWeight) * this.numberOfSheets) * this.quantity;
            },
            boxQuantity: function () {
                let boxes = this.totalWeight / 35;
                if (this.stitched) {
                    this.boxes = Math.ceil(boxes * stitchedMultiplier);
                    // this.$root.$emit('box-change', this.boxes);
                    return this.boxes
                } else {
                    this.boxes = Math.ceil(boxes);
                    // this.$root.$emit('box-change', this.boxes);
                    return Math.ceil(this.boxes);
                };
            },
        },
    }
</script>

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>boxcalculator2</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">
  <link rel="icon" href="../favicon.png">
  <title>Box Calculator</title>
  <!-- Bootstrap core CSS -->
  <link href="dist/css/bootstrap.min.css" rel="stylesheet">
  <!-- Custom styles for this template -->
  <link href="dist/sticky-footer.css" rel="stylesheet">
  <link rel="stylesheet" href="dist/build.css">
</head>

<body>
  <div class="container">
    <div class='row'>
      <div class='col'>
        <div id="app"></div>
      </div>
    </div>
  </div>
  <script src="dist/build.js"></script>
</body>

</html>

1 个答案:

答案 0 :(得分:1)

如果我的理解正确,那么您希望App的总盒数可以在每个Calculator各自确定其盒数时自动更新。一种方法是从Calculatoremit an event,当其盒数更改时,可以用watcher进行监视。

我们将在下面解决几个问题:

  1. Calculator(单个文件组件定义)存储在this.parts[]中是没有意义的(并且效率很低)。相反,它可以存储有意义的数据点,例如Calculator的输出。
  2. 代替DOM操作(即,向DOM查询元素以获取/设置其值),选择在Vue中对数据建模,并在模板中使用interpolation。这使Vue自动在目标元素中显示更新的值。它还消除了元素ID的分配(假设它们仅用于DOM操作),从而简化了模板以提高可读性。

存储计算器输出

App中,我们必须使用this.parts[]来跟踪每个part的计算结果(我们将在下面捕获)。我们将每个数组元素(即“部分”)定义为:

{
  boxes: 0 // box count for this part
}

此定义允许基于computed的{​​{1}}属性(稍后将定义)是反应性的。

因此,在.boxesaddPart()选项中:

data

// App.vue export default { // ... methods: { addPart() { this.parts.push({ boxes: 0 }); } }, data() { return { parts: [{ boxes: 0 }] } } } 的输出通知App

通常情况下,父母通过data to children via props,孩子交流data to parents with events。其他选择包括使用状态管理库,例如Vuex,但为简单起见,我们将在此处使用事件。

Calculator中,我们希望将Calculator值的更改通知给父(App),因此我们将添加一个{{3} }(例如,称为boxes),只要boxes-changed发生更改:

boxes

// Calculator.vue export default { //... watch: { boxes(value) { this.$emit('boxes-changed', value); } } } 中,我们将watcher,并将事件详细信息的值复制到当前App的{​​{1}}变量中,其中part是正在迭代boxes的当前数组元素。

part

parts[]的崩溃:

  • // App.vue <calculator v-for="(part, index) in parts" @boxes-changed="part.boxes = $event" :key="index"></calculator> -监听@boxes-changed="part.boxes = $event"发出的@boxes-changed="..."事件
  • boxes-changed-将<calculator>设置为事件详细信息的值

使part.boxes = $event处于反应状态

通过上述更改,我们有了使part.boxes的{​​{1}}具有反应性所需的工具:

  1. totalBoxCount更改为emits an event,将App的{​​{1}}字段加起来。每当totalBoxCount的数组元素更改时,将自动计算此属性。

    totalBoxCount
  2. .boxes的模板中,使用listen to the boxes-changed event显示this.parts[]

    this.parts[]
  3. 我们还可以从模板中删除 Total Boxes 按钮(以前用于手动触发计算):

     // App.vue
     export default {
       computed: {
         totalBoxCount() {
           // Note: Alternatively, use a simple for-loop to sum .boxes
           return this.parts
                   .filter(p => p.boxes && !Number.isNaN(p.boxes) // get only parts that have a positive `.boxes` value
                   .map(p => p.boxes)          // map object array into an integer array of `.boxes` values
                   .reduce((p,c) => p + c, 0); // sum all array elements
         },
       },
       data() {
         return {
           parts: [],
           // totalBoxCount: 0   // CHANGED INTO COMPTUED PROP ABOVE
         }
       }
     }
    

    及其关联的App处理程序:

    totalBoxCount

computed property