Как сбросить фильтр?

Есть вычисляемое свойство и связанный с ним инпут. При вводе запроса идет фильтрация массива, и при закрытии его нажатием на кнопку инпут очищается, вычисляемое свойство - пустая строка. Но почему-то на странице остается отфильтрованный массив элементов, а при очистке инпута Backspace'ом массив возвращается в исходное состояние. Как сбросить фильтр нажатием на кнопку?

Демка

Home.vue

<template>
  <div>
    <div class="header">
      <div class="container container-header">
        <router-link class="site-name" tag="a" to="/">{{sitename}}</router-link>

        <div class="search">
          <div class="search-input closed">
            <div class="container container-input">
              <input
                id="i"
                v-model="search"
                type="text"
                placeholder="Поиск..."
                autofocus
                class="search-game"
              >
            </div>
          </div>

          <button id="s" class="toggle-search"></button>
        </div>
      </div>
    </div>

    <section>
      <div class="container container--tabs">
        <ul class="tabs">
          <li class="active tabs-item">
            <a href="#">ВСЕ</a>
          </li>
          <li class="tabs-item">
            <a href="#">HTC</a>
          </li>
          <li class="tabs-item">
            <a href="#">PSVR</a>
          </li>
          <li class="tabs-item">
            <a href="#">PS4</a>
          </li>
        </ul>
      </div>
    </section>
    <div class="wrapper container">
      <div class="item" v-for="game in searchResult" :key="game.id">
        <router-link tag="div" :to="{ name : 'Id', params: {id: game.id}}" class="card">
          <div class="card-desc">
            <h3 v-text="game.title"></h3>
            <p v-text="game.description"></p>
          </div>
          <img v-bind:src="game.image" class="card-image">
        </router-link>
      </div>
    </div>
  </div>
</template>
<script>


export default {
  name: "home",
  data() {
    return {
      sitename: "Driv3r - Центр виртуальной реальности",
      publicPath: process.env.BASE_URL,
      search: "",
      games: []
    };
  },
  mounted() {
    this.$store.dispatch("loadGames");
    var i = document.querySelector(".search-input");
    var inp = document.querySelector(".search-game");
    var inputs = document.getElementsByTagName("input");
    var s = document.querySelector(".toggle-search");
    s.addEventListener("click", function() {
      if (i.classList.contains("closed")) {
        i.classList.remove("closed");
        i.classList.add("opened");
        inp.focus();
      } else {
        i.classList.add("closed");
        i.classList.remove("opened");
        inp.value = "";
        this.search = "";
        console.log(this.search);
      }
    });

    function all(css, element) {
      element = element || document;
      return [].slice.call(element.querySelectorAll(css));
    }

    let listItems = all("ul li");

    listItems.forEach(li => {
      all("a", li).forEach(a => {
        a.addEventListener("click", () => {
          listItems.forEach(li => li.classList.remove("active"));
          li.classList.add("active");
        });
      });
    });
  },
  computed: {
    // ...mapState(["games"]),
    searchResult() {
      // console.log(this.games);
      return this.$store.getters.searchGames(this.search);
    }
  }
};
</script>


store.js

import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
import VueAxios from "vue-axios";

Vue.use(Vuex);

export default new Vuex.Store({
  namespaced: true,
  state: {
    games: []
  },
  getters: {
    searchGames: state => query => {
      return state.games.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;
    },
    inputQuery(state, search) {
      state.search = search;
    }
  }
});
  • Вопрос задан
  • 638 просмотров
Решения вопроса 2
0xD34F
@0xD34F Куратор тега Vue.js
Теряете контекст в обработчике click (Home.vue), так что search там у вас - вовсе не свойство компонента. Сделайте функцию стрелочной (это чтобы вот прям сейчас заработало, а реально - весь этот шлак в mounted надо переписывать, откройте документацию vue, и разберитесь, как назначать обработчики событий, добавлять/удалять классы и т.д.).
Ответ написан
kleinmaximus
@kleinmaximus
Senior Full-stack Javascript Developer
Первое, и самое важное - не привязывайтесь к событиям DOM! Используйте обработчики событий Vue. Зачем с реактивными фреймворками типа Vue, React, Angular работать в стиле jQuery?

Уберите все из mounted(), кроме вызова dispatch.
Сделайте нормальную обработку событий.
В противном случае вся реактивность убивается.

И классы тоже надо выводить через computed свойства (на крайний случай через data), а не вставлять императивным методом.

<template>
   ...
   <button id="s" class="toggle-search" v-on:click="clear"></button>
   ...
</template>


export default {
  // ...,
  methods: {
    clear() {
      this.search = '';
    },
  },
  // ...,
};

Еще в store надо завести флаг статуса (не готов, готов, загружается, загружено...), чтобы соответствующим образом отображать всякие лоадеры, спиннеры и пр.. Думайте о пользователе сразу!

И советую подробно ознакомиться с документацией по Vue - она на понятном русском языке!
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

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

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