搜索和过滤功能仍然无法正常工作(Vue JS)

Search and filter features still doesn't work properly (Vue JS)

我正在弄清楚我的搜索和过滤功能如何才能正常工作。 我创建了一个搜索功能,并通过 stockdistancepricetime response 从搜索结果中筛选。我的搜索功能 运行 不错。但是,我做的过滤功能还是不行。

我想在进行搜索后进一步过滤搜索,当其中一个下拉列表发生变化时,有股票和距离等选项,搜索结果项也会根据过滤器发生变化(例如:股票) 是否可用。 还有其他过滤器,例如价格和时间响应。当我点击价格时,项目将按照最低价格到最高价格排序。当我点击时间响应时,搜索项目将按响应从快到晚的顺序排列。

案例

Type中,我选择BMW。然后我点击搜索按钮。将显示 2 个类型为 BMW 的项目结果。然后,在过滤器 Distance 中,我选择 500 KM。它应该只显示 1 个结果。但是过滤器不起作用。

如果有 6 件商品结果,我点击 price 商品将从最低价格到最高价格排序

我做了如下代码,谁能帮我解决这个问题?

new Vue({
  el: '#app',
  data: {
    selectedType: '',
    selectedCountry: '',
    selectedYear: '',
    selectedStock:'',
    selectedDistance:'',
    items: [{
        name: 'Carthy',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        stock: 'available',
        distance: '500',
        price: '1900',
        response: 'fast'
      },
            {
        name: 'Holand',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        stock: 'available',
        distance: '500',
        price: '1050',
        response: 'fast'
      },
      {
        name: 'Nolan',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        stock: 'available',
        distance: '500',
        price: '1000',
        response: 'fast'
      },
      {
        name: 'Edgar',
        type: 'bmw',
        year: '2020',
        country: 'belgium',
        stock: 'available',
        distance: '5000',
        price: '1200',
        response: 'fast'
      },
      {
        name: 'John',
        type: 'bmw',
        year: '2019',
        country: 'england',
        stock: 'available',
        distance: '500',
        price: '1500',
        response: 'fast'
      },
      {
        name: 'Axel',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        stock: 'sold',
        distance: '500',
        price: '1600',
        response: 'late'
      }
    ],
    searchResult: [],
    itemsToShow: 2,
    totalItems: 0,
    sortByPrice: true,
    sort: 'price',
    sortByTime: true,
    sort: 'time'
  },
  computed:{
    filterItem: function() {
      let filterStock = this.selectedStock,
        filterDistance = this.selectedDistance

      return this.searchResult.filter(function(item) {
        let filtered = true
        if (filterStock && filterStock.length > 0) {
          filtered = item.stock == filterStock
        }
        if (filtered) {
          if (filterDistance && filterDistance.length > 0) {
            filtered = item.distance == filterDistance
          }
        }
        return filtered
      })
    }
  },
  methods: {
    search: function() {
      let filterType = this.selectedType,
        filterCountry = this.selectedCountry,
        filterYear = this.selectedYear

      this.itemsToShow = 2;
      
      this.searchResult = this.items.filter(function(item) {
        let filtered = true
        if (filterType && filterType.length > 0) {
          filtered = item.type == filterType
        }
        if (filtered) {
          if (filterCountry && filterCountry.length > 0) {
            filtered = item.country == filterCountry
          }
        }
        if (filtered) {
          if (filterYear && filterYear.length > 0) {
            filtered = item.year == filterYear
          }
        }
        return filtered
      })
    },
    priceSort: function(){
        this.sortByPrice = !this.sortByPrice
      if(this.sortByPrice)
      this.sort = 'price'
    },
    timeSort: function(){
        this.sortByTime = !this.sortByTime
      if(this.sortByTime)
      this.sort = 'time'
    }
  },
  mounted() {
    this.search()
  }
})
.list-item{
  margin-top:50px;
}

#app{
  position:relative;
  padding-bottom: 200px;
}

span{
  margin: 0 15px;
  cursor:pointer;
}

.filter-box{
  margin-top:15px;
}

.card{
  box-shadow:0px 10px 16px rgba(0,0,0,0.16);
  width:400px;
  padding:20px 30px;
  margin-bottom:30px;
}

button{
  background-color: #1cf478;
  border:none;
  padding: 10px 25px;
  font-weight:bold;
  border-radius: 15px;
}

select{
  border:none;
  padding: 10px 15px;
  background-color:#c1c1c1; 
  border-radius:10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.1/vue.js"></script>

<div id="app">
  <div class="search-box">
    <select v-model="selectedType">
      <option value="" disabled selected hidden>Type</option>
      <option value="mercedes">Mercedes</option>
      <option value="bmw">BMW</option>
    </select>

    <select v-model="selectedCountry">
      <option value="" disabled selected hidden>Country</option>
      <option value="belgium">Belgium</option>
      <option value="england">England</option>
    </select>

    <select v-model="selectedYear">
      <option value="" disabled selected hidden>Year</option>
      <option value="2019">2019</option>
      <option value="2020">2020</option>
    </select>
    
    <button @click="search">Search</button>
  </div>
  
  <div class="filter-box">
    <h6>Filter:</h6>
    <select v-model="selectedStock" @change="filterItem">
      <option value="" disabled selected hidden>Stock</option>
      <option value="sold">Sold</option>
      <option value="available">Available</option>
    </select>
    
    <select v-model="selectedDistance" @change="filterItem">
      <option value="" disabled selected hidden>Kilometers</option>
      <option value="500">500 KM</option>
      <option value="5000">5000 KM</option>
      <option value="10000">10.000 KM</option>
    </select>
    
    <span class="price" @click="priceSort">Price</span>
    <span class="response" @click="timeSort">Time Response</span>
    
  </div>

  <section class="result">
    <div class="container-fluid">
        <div class="row list-item" v-for="(item, id) in searchResult" :key="id">
          <div class="col-3 card" v-if="id < itemsToShow">
            <p>Name: {{ item.name }}</p>
            <p>Car: {{ item.type }}</p>
            <p>Year: {{ item.year }}</p>
            <p>Country: {{ item.country }}</p>
            <p>Price: ${{ item.price }}</p>
            <p>stock: {{ item.stock }}</p>
            <p>distance: {{ item.distance }}</p>
          </div>
        </div>
      
        <div class="row">
          <div class="col-12">
            <button @click="itemsToShow += 1">Load More</button>
          </div>
        </div>
    </div>
  </section>
</div>

使用 @change 事件并调用 filterItem 计算 属性。每当 select 值更改时,将调用计算的 属性。

<select v-model="selectedStock" @change="filterItem">

请参阅此 codesandbox 以获得基于您的代码的工作演示。

我的改动

  1. searchResult 之上的 data 中添加 filterResult 以处理过滤结果,我们只将 filterResult 作为结果呈现。这样就把'search'和'filter'的逻辑分开了,逻辑更清晰。
  2. 每当过滤器 selected 值发生变化时,我们都会触发 filterItems 方法作为 @click 处理程序。 (之前您使用的是计算 属性 并且这不够简单,我们可以简单地为 @change 调用一个方法并更新 filter results 数据。
  3. 每当触发搜索时,我们都会重置过滤器 select 值,并显示所有搜索结果(filterResultsearchResult 相同,因为没有过滤器值) .
  4. 关于排序,对于两个排序span元素,我们只能更新this.sort数据,并使用watch来触发sortItems方法每当排序标准改变,会更简单。您可能需要根据需要调整 sortItems 方法。当然,您可以为这两个 'sort' 按钮编写两个单独的方法,这完全取决于您:)