这是我组件的计算属性:
methods: {
addFavoritePlace(place_id) {
axios.post('/api/add-favorite-place', { place_id: place_id })
.then(response => {
// I need here force command.
});
},
},
computed: {
filteredPlaces: function () {
var is_open;
if (this.showOpened) {
is_open = 'open'
} else {
is_open = 'close'
}
return this.singlePlaces.filter((j) => {
return j.name.toLowerCase().match(this.search.toLowerCase();
});
}
}
我的标记:
<span @click="addFavoritePlace(place.id)" class="favorite-btn active" v-if="place.is_favorited == true">
<i class="icon-heart"></i>
</span>
<span @click="addFavoritePlace(place.id)" class="favorite-btn" v-else>
<i class="icon-heart"></i>
</span>
我需要再次调用compute内部的过滤函数才能激活收藏夹按钮。
如果您想强制更新计算属性并重新计算其值,您可以简单地使用数据属性并在计算函数中提及该属性(您不必使用它,只需存在即可足够了),然后更改该数据属性;这将强制更新计算值。
这是代码:
data() {
return {
refreshKey: 0,
// ...
}
},
computed: {
myComputedValue() {
// just mentioning refreshKey
this.refreshKey;
// rest of the function that actualy do the calculations and returns a value
},
},
methods: {
myMethod() {
// the next line would force myComputedValue to update
this.refreshKey++;
// the rest of my method
},
},
Vue3
const now = computed(()=> new Date())
//manually update
now.effect.run()
这是我使用组合 API 的看法:
useRefreshable.ts
import { ref } from "vue";
export function useRefreshable<T>(getter: () => T): {
getter(): T;
refresh(): void;
} {
const refreshKey = ref(0);
return {
getter() {
refreshKey.value;
return getter();
},
refresh() {
refreshKey.value++;
},
};
}
useRefreshable.test.ts
import { computed, nextTick } from "vue";
import { useRefreshable } from "@/composition/useRefreshable";
describe("useRefreshable", () => {
test("", async () => {
let notReactiveValue = 1;
function getValue() {
return notReactiveValue;
}
const normalComputed = computed(getValue);
const refreshable = useRefreshable(getValue);
const refreshableComputed = computed(refreshable.getter);
expect(normalComputed.value).toEqual(1);
expect(refreshableComputed.value).toEqual(1);
notReactiveValue++;
await nextTick();
expect(normalComputed.value).toEqual(1);
expect(refreshableComputed.value).toEqual(1);
refreshable.refresh();
await nextTick();
expect(normalComputed.value).toEqual(1);
expect(refreshableComputed.value).toEqual(2);
});
});
您可以用多种不同的方式来包装它,例如:
import { computed, ComputedRef } from "vue";
import { useRefreshable } from "@/composition/useRefreshable";
export function useRefreshableComputed<T>(getter: () => T): {
readonly comp: ComputedRef<T>;
refresh(): void;
} {
const refreshable = useRefreshable(getter);
return {
comp: computed(() => refreshable.getter()),
refresh: refreshable.refresh,
};
}
您不需要手动强制更新计算属性。只要计算属性的相关值发生变化,就会自动重新计算。
在您的情况下,如果您修改
singlePlaces
,filteredPlaces
将自动更新。
但是,重要的是要注意 Vue 如何处理数组和对象的反应性,如文档中所述 (https://v2.vuejs.org/v2/guide/reactivity.html#For-Arrays)。
虽然您没有包含添加喜爱地点的特定代码,但您可能需要使用如下内容:
Vue.set(this.singlePlaces, indexOfItem, updatedItem)
这可确保 Vue 正确跟踪数组元素的更改。
首先,只需切换类,您就可以节省两倍的事件处理、两倍的 DOM 节点创建以及两倍的重新计算和重绘,而不是使用标记。另外,我不确定在 @click 事件中调用函数是否不会立即触发该函数,以防万一将其包装到匿名函数中。另外,请注意,我不是将
place.id
传递给 place
的整个 addFavoritePlace
对象引用:
<span
@click="() => addFavoritePlace(place)"
class="favorite-btn"
:class="{active: place.is_favorited}">
<i class="icon-heart"></i>
</span>
其次,部分
filteredPlaces
代码没有意义,因为您设置的变量不在其他地方使用也没有返回,因此垃圾收集器无论如何都会立即杀死它。相反,你可以选择:
computed: {
filteredPlaces () {
const search = this.search.toLowerCase()
return this.singlePlaces.filter((p) => {
return p.name.toLowerCase().includes(search)
});
}
}
最后,你可以只更新
singlePlaces
项目,它们会自动影响filteredPlaces,不需要做任何特殊的事情,如果你在每个 place
中没有 is_favorited 属性,你可以在 init 或 map
上使用它强制 Vue 使用 set
方法跟踪其更新。另外,正如我所说,我将传递整个 place
引用而不是 id
,这样我们就不必在堆栈中再次找到该元素:
methods: {
async addFavoritePlace (place) {
await axios.post('/api/add-favorite-place', { place_id: place.id })
this.$set(place, 'is_favorited', true)
},
},
这是 Vue 3 中的一个简单解决方案:
this._computedWatchers.computedName.run()
其中
computedName
是所需 computed
项目的名称。