Vue中的计算属性不计算

时间:2020-08-11 15:18:46

标签: javascript vue.js computed-properties

我有一个在Vue中构建的电子商务应用程序(SPA),下面是商店的快照

state: {
    cart: [],
    totalItems: {
      count: 0
    }
},
getters: {
    totalItems(){
      if(window.localStorage.totalItems){
        return JSON.parse(window.localStorage.totalItems)
      }
      else{
        let totalItems = { count: 0}
        return totalItems
      }
    }
},
mutations: {
    setCart(state, cart){
      state.cart = cart
      window.localStorage.cart = JSON.stringify(cart)
    },
    setTotalItems(state, totalItems){
      state.totalItems = totalItems
      window.localStorage.totalItems = JSON.stringify(totalItems)
    }
},
actions: {
    addToCart({ commit, getters }, productId){
      let cart = getters.cart
      let totalItems = getters.totalItems
      if(cart.length == 0){
        cart.push({id: productId, quantity: 1})
        totalItems.count++
      }
      else if(cart.find(({ id }) => id == productId)){
        let item = cart.find(({ id }) => id == productId)
        item.quantity++
        totalItems.count++
      }
      else{
        cart.push({id: productId, quantity: 1})
        totalItems.count++
       }
       commit('setCart', cart)
       commit('setTotalItems', totalItems)
    },
    setTotalItems({ commit }, totalItems){
      commit('setTotalItems', totalItems)
    }
}

在我的App.vue文件中,以下文件-

<template>
  <v-app>
    <v-app-bar
      app
      color="red"
      dark
    >
      <v-btn text to="/">Vue Shop</v-btn>

      <v-spacer></v-spacer>

      <v-btn text to="/cart">
        <v-badge v-if="totalItems.count" :content="totalItems.count"><v-icon>mdi-cart</v-icon></v-badge>
      </v-btn>

    </v-app-bar>

    <v-main>
      <router-view></router-view>
    </v-main>
  </v-app>
</template>

<script>


export default {
  name: 'App',
  components: {
  },
  computed: {
    totalItems(){
      return this.$store.getters.totalItems
    }
  }
};
</script>

当我加载站点时,我可以看到计算出的属性正在计算。但是,当我单击下面显示的Home.vue文件上的“添加到”按钮时,它应该是

  1. 调用addToCart方法
  2. 依次从商店中调度addToCart动作
  3. 在这里我要计算totalItems并使用setTotalItems突变来设置值

我面临的问题是,当我单击“添加到”按钮时,我可以看到在localStorage中更新了totalItems的值,但未在v-app-bar组件中反映出来。只有当我导航到其他页面然后返回主页时,该功能才能实现。

当我通过将值存储在状态而不是localStorage中来实现时,它可以正确反映,而不必导航到其他页面。

有没有办法在仍然使用localStorage而不是商店的情况下实现这一目标

<template>
      <v-container>
        <v-row>
          <v-col v-for="product in products" :key="product.id">
            <v-card width="300" height="300">
              <v-img :src=product.imgUrl width="300" height="200"></v-img>
              <v-card-title>
                {{ product.name }}
              </v-card-title>
              <v-card-text>
                ${{ product.price }}
                <v-btn small class="ml-16 primary" @click="addToCart(product.id)">Add to <v-icon>mdi-cart</v-icon></v-btn>
              </v-card-text>
            </v-card>
          </v-col>
        </v-row>
      </v-container>
    </template>
    
    <script>
    
    
    export default {
      name: 'Home',
      components: {
      },
      computed: {
        products(){
          return this.$store.getters.products
        },
        cart(){
          return this.$store.getters.cart
        }
      },
      methods: {
        addToCart(id){
          this.$store.dispatch('addToCart', id)
        }
      }
    }
    </script>

1 个答案:

答案 0 :(得分:0)

问题:本地存储没有反应性,因此您的使用者将永远不会重新评估。


解决方案 您可以重写您的getter,以便仅在状态尚未初始化时才从本地存储中检索值。然后,后续调用应直接访问状态,因为您正在更改mutator中的状态,这将触发对getter的重新评估,并因此对您的计算属性进行重新评估:

getters: {
    totalItems(state){
      if(state.totalItems.count < 0){
        return JSON.parse(window.localStorage.totalItems || '{count: 0}')
      }

      return state.totalItems;
    }
},

然后您可以用count初始化-1,这样对getter的第一个求值将进入本地存储。

通过引用您的getter中的totalItems属性,vue知道只要此属性发生更改就可以重新评估此getter。

这里的缺点是,在首次更改计数之前,您的获取器和状态不会同步。


您可能还可以通过调用localStorage来初始化状态,并将其从getter中消除。

state: {
   totalItems: {
      count: JSON.parse(window.localStorage.totalItems || '{count: 0}')
   }
},
getters: {
    totalItems(state){
      return state.totalItems;
    }
},

上行:您的状态和获取程序是同步的,但这也使您的获取程序变得多余。