Как сохранять выбранные пользователем элементы каталога?

Есть каталог, хочу организовать подобие вишлиста, если человек находится на странице элемента каталога, то при клике на кнопку сохранялся этот элемент в избранном, при повторном клике - удалялся.
Во Vuex добавил плагин 'persistedstate', вроде бы получаю нужное поведение, осталось как-то сохранять класс этой кнопки, которая бы относилась к определенному элементу каталога.
Есть мысль при сохранении элемента в массив wishlist добавлять свойство isLiked, а в mounted делать проверку на это свойство, но не знаю, как правильно все сделать.

Кнопка
<button ref="buttonLike" @click="putLike()" :class="buttonLike" class="like"></button>

computed: {
  buttonLike: function () {
    return {
      liked: this.isLiked
    }
  }
},
methods: {
  putLike: function () {
    if (this.$refs.buttonLike.classList.contains('liked')) 
    {
      this.isLiked = !this.isLiked
      this.$store.commit('removeGame', this.game)
    } else {
      this.isLiked = !this.isLiked
      this.$store.commit('addGame', this.game)
    }
  }
}

store.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import VueAxios from 'vue-axios'
import createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex)

export default new Vuex.Store({
  namespaced: true,
  state: {
    games: [],
    wishlist: []
  },
  plugins: [
    createPersistedState ()
  ],
  getters: {
    showAllGames: state => query => {
      return state.games.filter(game => {
        return game.title
          .toString()
          .toLowerCase()
          .includes(query.toString().toLowerCase())
      })
    },
    showHTCGames: state => query => {
      return state.games.filter(game => {
        return (game.category === 'htc' && game.title
          .toString()
          .toLowerCase()
          .includes(query.toString().toLowerCase()))
      })
    },
    showPSVRGames: state => query => {
      return state.games.filter(game => {
        return (game.category === 'psvr' && game.title
          .toString()
          .toLowerCase()
          .includes(query.toString().toLowerCase()))
      })
    },
    showPS4Games: state => query => {
      return state.games.filter(game => {
        return (game.category === 'ps' && game.title
          .toString()
          .toLowerCase()
          .includes(query.toString().toLowerCase()))
      })
    },
    showLikedGames: state => query => {
      return state.wishlist.filter(game => {
        return game.title
          .toString()
          .toLowerCase()
          .includes(query.toString().toLowerCase())
      })
    }
  },
  actions: {
    loadGames ({ commit }) {
      axios
        .get('games.json')
        .then(r => r.data.games)
        .then(games => {
          commit('SET_GAMES', games)
        })
    }
  },
  mutations: {
    SET_GAMES (state, games) {
      state.games = games
    },
    addGame (state, game) {
      state.wishlist.push(game)
    },
    removeGame (state, game) {
      state.wishlist.splice(game, 1)
    }
  }
})
  • Вопрос задан
  • 244 просмотра
Решения вопроса 1
0xD34F
@0xD34F Куратор тега Vue.js
Элементы games должны иметь уникальное свойство, которое бы позволяло их идентифицировать, id. Если такого нет - срочно добавляйте. Сохранять в localStorage следует эти id. Так что добавим в стейт соответствующий массив:

state: {
  wishlistIds: [],
  ...

И укажем его в настройках persistedstate (да, можно сохранять не весь стейт, а только некоторые элементы):

plugins: [
  createPersistedState({
    paths: [ 'wishlistIds' ],
  }),
  ...

Массив wishlist - из стейта переносим в геттеры:

getters: {
  wishlist: state => state.games.filter(n => state.wishlistIds.includes(n.id)),
  ...

Добавление/удаление, соответственно:

mutations: {
  addGame(state, gameId) {
    if (!state.wishlistIds.includes(gameId)) {
      state.wishlistIds.push(gameId);
    }
  },
  removeGame(state, gameId) {
    const index = state.wishlistIds.indexOf(gameId);
    if (index !== -1) {
      state.wishlistIds.splice(index, 1);
    }
  },
  ...

В компонент, отображающий элементы games, добавим вычисляемое свойство liked, которое будет указывать, находится ли текущий элемент в wishlist и управлять добавлением/удалением:

computed: {
  liked: {
    get() {
      return this.$store.state.wishlistIds.includes(this.game.id);
    },
    set(val) {
      this.$store.commit(val ? 'addGame' : 'removeGame', this.game.id);
    },
  },
  ...

<button @click="liked = !liked" :class="{ liked }" class="like"></button>

Ну а свойство isLiked и метод putLike - это мусор, их следует вырезать.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы