需要一个解决方案来按多个价格范围过滤产品

Need a solution to filter products by multiple price ranges

我是 VueJS 的新手。 我有一个产品列表,我想按价格范围过滤这些产品。所以,我构建了一个组件(filter-sidebar),它是一个通过单选按钮包含过滤器类型(价格,品牌..等)的侧边栏,我想过滤产品价格,并且具有选定价格范围的产品将显示在父级组件。

&& 如果有其他更好的过滤方法我会很高兴:)

{
    "products":[
        {
            "id":1,
            "name": "Apple Watch Series 5",
            "price": 339.99,
            "rating": 4,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/1.3b312012.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"            },
        {
            "id":2,
            "name": "Apple iPhone 11 (64GB, Black)",
            "price": 669.99,
            "rating": 5,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/2.1aba2cea.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"
        },
        {
            "id":3,
            "name": "Apple iMac 27-inch",
            "price": 999.99,
            "rating": 4,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/3.29c766f8.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"
        },
        {
            "id":4,
            "name": "OneOdio A71 Wired Headphones",
            "price": 49.99,
            "rating": 3,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/4.73f34744.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"
        },
        {
            "id":5,
            "name": "Apple - MacBook Air® (Latest Model) - 13.3 Display - Silver",
            "price": 999.99,
            "rating": 4,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/5.c5b188e5.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"
        },
        {
            "id":6,
            "name": "Switch Pro Controller",
            "price": 429.99,
            "rating": 3,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/6.833c8951.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "apple"
        },
        {
            "id":7,
            "name": "Google - Google Home - White/Slate fabric",
            "price": 129.29,
            "rating": 4,
            "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/1.3b312012.png",
            "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.",
            "brand": "google"
        },

子组件(过滤侧边栏):

<template>
    <div class="sidebar">
        <h5 class="filter-heading">Filters</h5>
        <div class="sidebar-body">
          <h5 class="filter-title">Multi Range</h5>
          <div class="multi-range">
            <div class="multi-range-group">
              <label for="all">
                <input
                  id="all"
                  type="radio"
                  value="all"
                  name="price"
                  v-model="selectPrice"
                  class="custom-control-input"
                  @change="filterRangePrice()"
                  checked
                />
                All</label
              >
            </div>
            <div class="multi-range-group">
              <label for="10">
                <input
                  id="10"
                  type="radio"
                  value="10"
                  name="price"
                  v-model="selectPrice"
                  class="custom-control-input"
                  @change="filterRangePrice()"
                />
                &lt;= </label
              >
            </div>
            <div class="multi-range-group">
              <label for="10-100">
                <input
                  id="10-100"
                  type="radio"
                  value="10-100"
                  name="price"
                  v-model="selectPrice"
                  class="custom-control-input"
                  @change="filterRangePrice()"
                />
                 - 0</label
              >
            </div>
            <div class="multi-range-group">
              <label for="100-500">
                <input
                  id="100-500"
                  type="radio"
                  name="price"
                  class="custom-control-input"
                  value="100-500"
                  v-model="selectPrice"
                  @change="filterRangePrice()"
                />
                0 - 0</label
              >
            </div>
            <div class="multi-range-group">
              <label for="500">
                <input
                  id="500"
                  type="radio"
                  class="custom-control-input"
                  value="500"
                  name="price"
                  v-model="selectPrice"
                  @change="filterRangePrice()"
                />
                &gt;= 0</label
              >
            </div>
          </div>
</template>

<script>
export default {
  name: "FilterSidebar",

  data() {
    return {
      selectPrice: null,
    };
  },

  methods: {
    filterRangePrice() {
      this.$emit("filterPrice", this.selectPrice);
    }
  }
};
</script>

父组件:

<template>

  <div>
    <filter-sidebar @filter-price="filterByPrice" />
  </div>

 <div class="grid-view" v-if="layout === 'grid'">
      <div
        v-for="prod of (handleRangePrice, filterProducts.slice(0, 7))"
        :key="prod.id"
        class="card"
      >
        <div class="card-body">
          <div class="item-img">
            <a href="#">
              <img :src="prod.img" :alt="prod.name" class="product-image" />
            </a>
          </div>

          <div class="item-rating">
            <ul>
              <li><span class="material-icons"> star </span></li>
              <li><span class="material-icons"> star </span></li>
              <li><span class="material-icons"> star </span></li>
              <li>
                <span class="material-icons-outlined"> star_border </span>
              </li>
            </ul>
          </div>

          <h5 class="item-price">${{ prod.price }}</h5>
          <div class="item-details">
            <h4 class="item-title">{{ prod.name }}</h4>
            <p class="item-description">{{ prod.discription }}</p>
          </div>
        </div>

        <div class="item-options">
          <a href="#" class="wishlist">
            <span class="material-icons-outlined"> favorite_border </span>
            <span>Wishist</span>
          </a>
          <a href="#" class="addCart">
            <span class="material-icons-outlined"> shopping_cart </span>
            <span>View In Cart</span>
          </a>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
import FilterSidebar from "./FilterSidebar.vue";

export default {
  name: "search-bar",
  components: {
    FilterSidebar,
  },

  data() {
    return {
      productData: require("@/data/store-data.json"),
      selectedPrice: null,
     
    };
  },

  computed: {
    filterProducts: function () {
      let realProducts = this.productData.products;
      if (this.searchValue != "" && this.searchValue) {
        return realProducts.filter((prod) => {
          return prod.name
            .toLowerCase()
            .includes(this.searchValue.toLowerCase());
        });
      }
      return realProducts;
    },

    // return filtered products by price
    handleRangePrice: function () {
      let allProducts = this.productData.products;
      if (this.selectedPrice) {
        switch (this.selectedPrice) {
          case "all":
            allProducts;
            break;

          case "10":
            allProducts = allProducts.filter((item) => {
              item.price <= this.selectedPrice;
            });
            break;

          case "10-100":
            allProducts = allProducts.filter((item) => {
              item.price <= 100 && item.price >= 10;
            });
            break;

          case "100-500":
            allProducts = allProducts.filter((item) => {
              item.price <= 500 && item.price >= 100;
            });
            break;

          case "500":
            allProducts = allProducts.filter((item) => {
              item.price >= this.selectedPrice;
            });
            break;
        }
      }
      return allProducts;
    },
},

 methods: {
    filterByPrice: function (price) {
      this.selectedPrice = price;
    },
  },
};
</script>

另一种方式,请看:

Vue.component('FilterSidebar', {
  template: `
  <div class="sidebar">
    <h5 class="filter-heading">Filters</h5>
    <div class="sidebar-body">
      <h5 class="filter-title">Multi Range</h5>
      <div class="multi-range">
        <div class="multi-range-group" v-for="range in ranges" :key="range.lbl">
          <label :for="range.lbl">
            <input :id="range.lbl" type="radio" :value="{min: range.min, max: range.max}"
              name="price" v-model="selectPrice" class="custom-control-input"
              @change="filterRangePrice" />
            {{range.lbl}}</label
          >
        </div>
      </div>
    </div>
  </div>
  `,
  data() {
    return {
      selectPrice: {min: 0, max: 1000000},
      ranges: [{lbl: 'All', min: 0, max: 1000000}, {lbl: '<=', min: 0, max: 10}, {lbl: ' - 0', min: 10, max: 100}, {lbl: '0 - 0', min: 100, max: 500}, {lbl: '>=500', min: 500, max: 1000000}]
    };
  },
  methods: {
    filterRangePrice() {
      this.$emit("filter-price", this.selectPrice);
    }
  }
})

new Vue({
  el: '#demo',
  data() {
    return {
      productData: {"products":[{"id":1, "name": "Apple Watch Series 5", "price": 339.99, "rating": 4, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/1.3b312012.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":2, "name": "Apple iPhone 11 (64GB, Black)", "price": 669.99, "rating": 5, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/2.1aba2cea.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":3, "name": "Apple iMac 27-inch", "price": 999.99, "rating": 4, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/3.29c766f8.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":4, "name": "OneOdio A71 Wired Headphones", "price": 49.99, "rating": 3, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/4.73f34744.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":5, "name": "Apple - MacBook Air® (Latest Model) - 13.3 Display - Silver", "price": 999.99, "rating": 4, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/5.c5b188e5.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":6, "name": "Switch Pro Controller", "price": 429.99, "rating": 3, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/6.833c8951.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "apple"}, {"id":7, "name": "Google - Google Home - White/Slate fabric", "price": 129.29, "rating": 4, "img": "https://pixinvent.com/demo/vuexy-vuejs-admin-dashboard-template/demo-1/img/1.3b312012.png", "discription": "On Retina display that never sleeps, so it’s easy to see the time and other important information, without raising or tapping the display. New location features, from a built-in compass to current elevation, help users better navigate their day, while international emergency calling1 allows customers to call emergency services directly from Apple Watch in over 150 countries, even without iPhone nearby. Apple Watch Series 5 is available in a wider range of materials, including aluminium, stainless steel, ceramic and an all-new titanium.", "brand": "google"},]},
      selectedPrice: null,
      layout: 'grid', 
      filteredData: [],
      searchValue: ''
    };
  },
  methods: {
    filterByPrice(price) {
      this.selectedPrice = price
      if (this.selectedPrice) {
        this.filteredData =  this.productData.products.filter(item => 
          item.price >= price.min && item.price <= price.max
        );
      } else this.filteredData = this.productData.products
    },
    filterProducts() {
      if (this.searchValue != "" && this.searchValue) {
        this.filteredData = this.productData.products.filter((prod) => {
          return prod.name
            .toLowerCase()
            .includes(this.searchValue.toLowerCase());
        });
      }
    },
  },
  mounted() {
    this.filteredData = [...this.productData.products]
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp" rel="stylesheet">
<div id="demo">
  <div>
    <input v-model="searchValue" @input="filterProducts" />
    <filter-sidebar @filter-price="filterByPrice"></filter-sidebar>
  </div>
  <div class="grid-view" v-if="layout === 'grid'">
    <div v-for="prod in filteredData" :key="prod.id" class="card">
      <div class="card-body">
        <div class="item-img">
          <a href="#"><img :src="prod.img" :alt="prod.name" class="product-image" /></a>
        </div>
        <div class="item-rating">
          <ul>
            <li><span class="material-icons"> star </span></li>
            <li><span class="material-icons"> star </span></li>
            <li><span class="material-icons"> star </span></li>
            <li>
              <span class="material-icons-outlined"> star_border </span>
            </li>
          </ul>
        </div>
        <h5 class="item-price">${{ prod.price }}</h5>
        <div class="item-details">
          <h4 class="item-title">{{ prod.name }}</h4>
          <p class="item-description">{{ prod.discription }}</p>
        </div>
      </div>
      <div class="item-options">
        <a href="#" class="wishlist">
          <span class="material-icons-outlined"> favorite_border </span>
          <span>Wishist</span>
        </a>
        <a href="#" class="addCart">
          <span class="material-icons-outlined"> shopping_cart </span>
          <span>View In Cart</span>
        </a>
      </div>
    </div>
  </div>
</div>