Vue.js计算属性未触发。

4

Vue JS的计算属性在使用此标记时不会被触发

<!-- language: lang-html -->
<p>£{{plant_price}}</p>

    <div v-if="selected.plant.variations.length > 0 ">
      <select v-model="selected.plant.selected_variation" class="form-control">
        <!-- inline object literal -->
        <option v-for="(variation, i) in selected.plant.variations" :selected="variation.id == selected.plant.selected_variation ? 'selected' : ''":value="variation.id">
          {{variation.name}}
        </option>
      </select>
    </div>

<!-- language: lang-js -->
var app = new Vue({
  el: '#vueApp',
  data: {
    selected: {
      type: {a: '' , b: ''},
      vehicle: '',
      plant: {
      }
    },
  computed: {
plant_price: function() {
  if (this.selected.plant.variations.length > 0 ) {
      var variant = _.find(this.selected.plant.variations, {id: this.selected.plant.selected_variation });
      return variant.price;
  } else {
    return this.selected.plant.price;
  }
}
...

selected.plant 是通过单击植物来填充的 - 触发 updateSelected 方法。

<div class="col-sm-4" v-for="(plant, i) in step2.plants">
          <div v-on:click="updateSelected(plant)" ....

 methods: {
      updateSelected: function(plant) {
             this.selected.plant = plant; // selected plant
             if (this.selected.plant.variations.length > 0 ) {
                 this.selected.plant.selected_variation = this.selected.plant.variations[0].id; // set the selected ID to the 1st variation

我已经通过调试器进行了检查,可以看到所有正确的属性都可用。
selected:Object
    type:Object
    vehicle: "Truck"
    plant:Object
       id:26
       price:"52"
       regular_price:"100"
       selected_variation:421
       variations:Array[2]
          0:Object
              id:420
              name:"small"
              price:52000
              regular_price:52000
          1:Object
               etc...

我有一个计算属性,应该根据selected.plant.selected_variation的值更新plant_price

我获取selected.plant.selected_variation并搜索变体以检索价格。如果没有变体存在,则使用植物价格。

每个产品上都有一种方法可以更新所选植物。点击产品会填充selected.plant并触发计算出的plant_price来更新价格(因为选择的selected.plant.selected_variation的值已更改)。

但是,计算得出的plant_price并未通过选择触发。选择新的变体确实会更新selected.plant.selected_variation,但我的plant_price似乎未被触发。


因此,我通过取消嵌套selected.plant.selected_variation来重构代码。我现在将其作为数据对象挂起:

data = {
    selected_variation: ''
    }

并将我的计算机属性更改为引用数据作为this.selected_variation。我的计算机属性现在有效了???这对我来说毫无意义?

2个回答

6

selected.plant.selected_variation 没有响应式,因为你在 VM 创建后才设置它,所以 VM 看不到你对它所做的任何更改。

你可以使用 Vue.set() 使其具备响应式。

AJAX 完成后,请调用:

Vue.set(selected, 'plant', {Plant Object})

谢谢@SpeekaDievs,抱歉 - 我没有解释清楚...我会更新我的问题。 - Rob
你的回答对于我所描述的问题是正确的,只是我没有很好地描述清楚。 - Rob
你把这行代码放在哪里?能否请您解释一下参数是什么意思?谢谢。 - Alexis.Rolland

1

你有两种方法可以做到这一点,你正在处理的是一个嵌套对象,所以如果你想将 selected 的更改通知给其他人,你必须使用

this.$set(this.selected, 'plant', 'AJAX_RESULT')

在这段代码中,我在created方法中使用了setTimeout来模拟Ajax调用。
另一种方法是,你可以在观察器中监听selected的嵌套属性的变化,而不是将plant_price作为一个computed属性,然后在handler中更新plant_price。你可以查看代码片段中的plant_price_from_watch

Vue.component('v-select', VueSelect.VueSelect);

const app = new Vue({
  el: '#app',
  data: {
    plant_price_from_watch: 'not available',
    selected: {
      type: {a: '' , b: ''},
      vehicle: "Truck"
    }
  },
  computed: {
    plant_price() {
      return this.setPlantPrice();
    }
  },
  watch: {
    selected: {
      handler() {
        console.log('changed');
        this.plant_price_from_watch = this.setPlantPrice();
      },
      deep: true
    }
  },
  created() {
    setTimeout(() => {
      this.$set(this.selected, 'plant', {
        id: 26,
        price: '52',
        regular_price: '100',
        selected_variation: 421,
        variations: [
          {
            id: 420,
            name: "small",
            price: 52000,
            regular_price: 52000
          },
          {
            id: 421,
            name: "smallvvsvsfv",
            price: 22000,
            regular_price: 22000
          }
        ]
      })
    }, 3000);
  },
  methods: {
    setPlantPrice() {
      if (!this.selected.plant) {
        return 'not available'
      }
      if (this.selected.plant.variations.length > 0 ) {
          const variant = _.find(this.selected.plant.variations, {id: this.selected.plant.selected_variation });
          return variant.price;
      } else {
        return this.selected.plant.price;
      }
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
  <p>£{{plant_price}}</p>
  <p>£{{plant_price_from_watch}}</p>
  <div v-if="selected.plant && selected.plant.variations.length > 0 ">
    <select v-model="selected.plant.selected_variation" class="form-control">
      <!-- inline object literal -->
      <option v-for="(variation, i) in selected.plant.variations" :selected="variation.id == selected.plant.selected_variation ? 'selected' : ''":value="variation.id">
        {{variation.name}}
      </option>
    </select>
  </div>
</div>


谢谢Kevlai22 - 我恐怕已经编辑了我的问题,因为我发布的那个问题充满了错误... 请查看问题的编辑。 - Rob
@Rob,我不太理解你的updateSelected方法,你传入的a是什么?? - kevguy
整个植物对象。我有一个植物列表,我通过ajax渲染出来(此列表是通过ajax获取的)。在每个植物上,我附加了一个更新方法。我只需将整个植物作为参数传递给更新函数。这样就可以更新所选的植物。我通过将a更改为plant来提高问题的清晰度。 - Rob
@Rob,实际上有一个单独的植物列表(我们称之为plantList),通过ajax调用检索,并且updateSelected将更新要放入selected.plant中的内容,这将影响在下拉列表中选择什么? - kevguy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接