首页 > 解决方案 > 搜索和过滤功能仍然无法正常工作(Vue JS)

问题描述

我正在弄清楚我的搜索和过滤功能如何正常工作。stock我创建了一个搜索功能并按、distanceprice和过滤搜索结果time 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>

标签: javascriptvue.jsvuejs2v-forv-model

解决方案


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

我的改变

  1. 添加filterResult在处理过滤结果data的顶部searchResult,我们只渲染filterResult为结果。这将分离“搜索”和“过滤”的逻辑,逻辑更清晰。
  2. 每当过滤器选择的值发生变化时,我们都会触发filterItems方法作为@click处理程序。(以前您使用的是计算属性,这不够简单,我们可以简单地调用一个方法来@change更新filter results数据。
  3. 每当触发搜索时,我们都会重置过滤器选择值,并显示所有搜索结果(filterResultsearchResult没有过滤器值相同)。
  4. 至于排序,对于这两个排序span元素,我们只能更新this.sort数据,只要排序条件发生变化,就使用watchto triggersortItems方法,这样会更简单一些。您可能需要根据需要调整sortItems方法。当然,您可以为这两个“排序”按钮编写两个单独的方法,这完全取决于您:)

推荐阅读