VueJS 2 - 观察数组和/或对象内的属性

时间:2017-12-20 16:32:35

标签: javascript vue.js vuejs2

问题示例:https://jsfiddle.net/hxv5bLqt/

我有一个包含2个级别(数组)的数据结构。第一级是“部分”,第二级是“项目”,它们位于每个“部分”内。还有一个变量存储每个项目值的总值。示例工作如下:每次用户在某个值字段中键入内容或删除值时,必须重新计算总数。

但是,我对示例解决方案不满意,因为我需要映射应该调用“this.recompute()”方法的所有地方,并且通过监视或计算属性,这可以解决以更清晰的方式,清洁和反应。

但是,我无法实现“监视”或“计算属性”,可以看到数组内部对象属性的更改。

对于“手表”案例,我认为理想和我认为可行的是:

watch: {
    'parts.X.items.Y.value': function(oldValue, newValue) {
         this.recompute()
    }
}

“X”和“Y”表示要观察的字段位于数组的任何位置的变量。

这样,每次用户点击按钮删除项目或在值字段中键入内容时,都会触发手表。但这不起作用。

这样,每次用户点击按钮删除项目或在值字段中键入内容时,都会触发手表。但是这不起作用,我需要映射应该调用“this.recompute()”方法的所有点,如下所示:

onClickRemoveItem(event, part, item) {
    ...
    this.recompute() // RECOMPUTE HERE.
},

onKeyupItemValue(event) {
    this.recompute() // RECOMPUTE HERE.
},

我认为这不是解决问题的好方法,因为如果还有10个地方应该调用“this.recompute()”方法,那么很难记住所有的调用位置。

有一种方法可以更优雅的方式做到这一点吗?

1 个答案:

答案 0 :(得分:0)

如果你使你的总数成为计算属性,那么你可以免费获得更多的反应性(意味着你不必监听项目值的更新或明确地重新计算任何东西)。请参阅此处的答案以了解具体实施:https://jsfiddle.net/16wk9gre/

HTML

<script src="https://unpkg.com/vue"></script>
<div id="app">
  <h3>Tests</h3>
  <ul>
    <li v-for="part in parts">
      <span>{{ part.name }}</span>
      <ul>
        <li v-for="item in part.items">
          R$ <input type="number" v-model="item.value">
          <button type="button" @click="onClickRemoveItem($event, part, item)">Remove</button>
        </li>
        <p>
           Part subtotal: ${{ part.items.reduce((acc, item) => acc + parseFloat(item.value), 0) }}
        </p>
        <p>
          Part subtotal (alternate): ${{ calculatePartSubtotal(part.items) }}
      </p>
      </ul>
    </li>
  </ul>

  <p><strong>Total value:</strong>R$ {{ total }}</p>
</div>

JS

new Vue({
  el: '#app',
  data() {
    return {
      // Define some nested mock data.
      parts: [
        { id: 1, name: 'Part 1', items: [{ id: 1, value: 10.00 }, { id: 2, value: 5.00 }] },
        { id: 2, name: 'Part 2', items: [{ id: 3, value: 15.00 }] }
      ]
   }
 },
computed: {
  total () {
    let total = 0.0
    for (let i = 0; i < this.parts.length; i++) {
      for (let j = 0; j < this.parts[i].items.length;; j++) {
        total += parseFloat(this.parts[i].items[j].value)
      }
    }
    return total
  }
},
methods: {
  calculatePartSubtotal (items) {
    return items.reduce((acc, item) => acc + parseFloat(item.value), 0)
  },
  // Remove an item of a part.
  onClickRemoveItem(event, part, item) {
    let index = part.items.findIndex(e => e.id === item.id)
    this.$delete(part.items, index)
   }
 }
})