在 Vue 中计算 属性 不计算
Computed property in Vue not calculating
我有一个用 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 文件上的 'Add to' 按钮时,它应该是
- 调用 addToCart 方法
- 依次从商店调度 addToCart 操作
- 我在哪里计算 totalItems 并使用 setTotalItems 突变设置值
我面临的问题是,当我单击 'Add to' 按钮时,我可以看到 totalItems 的值在 localStorage 中更新,但它没有反映在 v-app-bar 组件中。只有当我导航到另一个页面然后返回主页时,它才会这样做。
当我通过将值存储在 state 而不是 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>
问题 本地存储没有反应,因此您的 getter 永远不会重新评估。
解决方案
您可以重写 getter 以便它仅在状态尚未初始化时从本地存储中检索值。随后的调用应该直接访问该状态,因为您正在更改您的增变器中的状态,这将触发对您的 getter 的重新评估,因此您的计算 属性:
getters: {
totalItems(state){
if(state.totalItems.count < 0){
return JSON.parse(window.localStorage.totalItems || '{count: 0}')
}
return state.totalItems;
}
},
然后您可以使用 -1
初始化您的 count
,因此 getter 的第一次评估将查看本地存储。
通过在你的 getter 中引用 totalItems
属性,vue 知道只要这个 属性 改变就重新计算这个 getter。
这里的缺点是,您的 getter 和您的状态在第一次更改计数之前不会同步。
您可能还可以通过调用 localStorage 来初始化您的状态,然后将其从 getter.
中删除
state: {
totalItems: {
count: JSON.parse(window.localStorage.totalItems || '{count: 0}')
}
},
getters: {
totalItems(state){
return state.totalItems;
}
},
好处:你的状态和 getter 是同步的,但这也会让你的 getter 变得多余。
我有一个用 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 文件上的 'Add to' 按钮时,它应该是
- 调用 addToCart 方法
- 依次从商店调度 addToCart 操作
- 我在哪里计算 totalItems 并使用 setTotalItems 突变设置值
我面临的问题是,当我单击 'Add to' 按钮时,我可以看到 totalItems 的值在 localStorage 中更新,但它没有反映在 v-app-bar 组件中。只有当我导航到另一个页面然后返回主页时,它才会这样做。
当我通过将值存储在 state 而不是 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>
问题 本地存储没有反应,因此您的 getter 永远不会重新评估。
解决方案 您可以重写 getter 以便它仅在状态尚未初始化时从本地存储中检索值。随后的调用应该直接访问该状态,因为您正在更改您的增变器中的状态,这将触发对您的 getter 的重新评估,因此您的计算 属性:
getters: {
totalItems(state){
if(state.totalItems.count < 0){
return JSON.parse(window.localStorage.totalItems || '{count: 0}')
}
return state.totalItems;
}
},
然后您可以使用 -1
初始化您的 count
,因此 getter 的第一次评估将查看本地存储。
通过在你的 getter 中引用 totalItems
属性,vue 知道只要这个 属性 改变就重新计算这个 getter。
这里的缺点是,您的 getter 和您的状态在第一次更改计数之前不会同步。
您可能还可以通过调用 localStorage 来初始化您的状态,然后将其从 getter.
中删除state: {
totalItems: {
count: JSON.parse(window.localStorage.totalItems || '{count: 0}')
}
},
getters: {
totalItems(state){
return state.totalItems;
}
},
好处:你的状态和 getter 是同步的,但这也会让你的 getter 变得多余。