我正在尝试在我的 Vue 组件之一中使用本地存储,并且我需要能够依赖于那里已经存在的所有内容进行渲染,并在单击按钮时切换本地存储中的一些数据。此外,UI 上也应该根据更改内容进行更改。这是我的组件:
<template>
<div class="card">
<div>
<img :src="image" alt="character-image"/>
</div>
<div class="cardInfo">
<p class="cardTitle">{{ name }}</p>
<span>{{ species }}</span> - <span>{{ status }}</span>
<Button
:buttonText="buttonText"
class="addToFavouritesBtn"
@click="toggleFavourites"
>
</Button>
</div>
</div>
</template>
<script setup lang="ts">
import { defineProps, computed } from "vue";
import Button from '../components/Button.vue';
import useLocalStorage from '../utils/useLocalStorage';
const props = defineProps<{
characterData: {
id: string,
name: string,
image: string,
species: string,
status: string
}
}>();
const { id, name, image, species, status } = props.characterData;
const favourites = useLocalStorage([], 'favouriteCharacters');
const buttonText = computed(() => {
return favourites.value.some(character => character.id === id) ? 'Remove from Favourites' : 'Add to Favourites';
});
const toggleFavourites = () => {
const index = favourites.value.findIndex((character) => character.id === id);
if (index === -1) {
console.log(1)
// Not in favourites, add it
favourites.value.push(props.characterData);
} else {
console.log(2)
// Already in favourites, remove it
favourites.value.splice(index, 1); // This will remove the item at the found index
}
};
</script>
我还使用可组合函数,以便能够通过整个应用程序重用对本地存储的访问
import { ref, watch } from "vue";
export default function useLocalStorage(initialValue, key) {
const storedValue = window.localStorage.getItem(key);
const val = ref(storedValue ? JSON.parse(storedValue) : initialValue);
watch(val, (newValue) => {
window.localStorage.setItem(key, JSON.stringify(newValue));
}, { deep: true });
return val;
}
但问题是,当我单击“添加到收藏夹”按钮时,它只是替换本地存储中的现有对象,删除功能也不起作用。事实上,即使这个元素已经存在于本地存储中,我们也从未遇到过放置 console.log(2) 的 else 语句。
我还不确定为什么,但我已经通过将与本地存储相关的所有逻辑移至父组件来解决我的问题。
<template>
<div class="filterBar">
<div class="container">
<ButtonGroup :groupCategories="categoriesData"/>
{{ activeButtonName.activeButton }}
<!-- <div v-if="isLoading" class="spinner">Loading...</div>-->
<button @click="prevPage">Previous</button>
<button @click="nextPage">Next</button>
</div>
</div>
<div class="container">
<div
class="cardWrapper"
>
<CharacterCard
v-for="character in characters"
:key="character.id"
:characterData="character"
:favorite="favourites"
:handleClick="toggleFavourites"
/>
</div>
</div>
</template>
<script setup lang="ts">
import {ref} from "vue";
import {watch} from "vue";
import ButtonGroup from "../components/ButtonGroup.vue";
import CharacterCard from '../components/CharacterCard.vue';
import {useButtonGroup} from "@/stores/buttonGroup";
import {usePagination} from "@/utils/usePagination";
import useLocalStorage from '../utils/useLocalStorage';
const categoriesData = ["All", "Human", "Animal", "Alien"];
const activeButtonName = useButtonGroup();
const url = ref("");
const favourites = useLocalStorage([], 'favouriteCharacters');
const toggleFavourites = (id, data) => {
let dataCopy = [...favourites.value];
const index = dataCopy.findIndex((character) => character.id === id);
if (index === -1) {
dataCopy.push(data);
} else {
dataCopy = dataCopy.filter(character => character.id !== id);
}
favourites.value = dataCopy;
};
watch(activeButtonName, (newValue, oldValue) => {
url.value = newValue.getActiveButton.toLowerCase() === 'all'
? 'https://rickandmortyapi.com/api/character'
: `https://rickandmortyapi.com/api/character?species=${newValue.getActiveButton.toLowerCase()}`;
});
const {data: characters, isLoading, info, nextPage, prevPage} = usePagination(url);
</script>