代码之家  ›  专栏  ›  技术社区  ›  Jack

如何从javascript的多个属性中过滤数组的JSON对象

  •  0
  • Jack  · 技术社区  · 4 年前

    我可以管理两个过滤器,如果其中一个在 if (filtered) 第二个条件在里面声明。

    不过,我想知道不止两个选项的情况如何。代码附在下面。

    // Trunkera beskrivning
    Vue.filter("truncate", function (value, limit) {
      if (value.length > limit) {
    value = value.substring(0, limit - 3) + "...";
      }
      return value;
    });
    
    new Vue({
      el: "#app",
      data: function () {
    return {
      visible: false,
      boats: null,
      filter: {
        options: {
          brands: [],
          model: [],
          engineBrands: [],
          engineModels: [],
          type: [],
          maxPrice: null,
          minPrice: null,
          years: [],
        }
      },
      selected: {
        options: {
          brand: null,
          length: 1000,
          condition: null,
          engineBrand: null,
          engineModel: null,
          engineType: null,
          fridge: null,
          kitchen: null,
          type: null,
          shower: null,
          year: null,
          water: null,
          wc: null
        }
      }
    };
      },
      created() {
    const vm = this;
    fetch(
        'https://www.sokbat.se/api/Ad?json=%7b"CompanyId":"5055","AdCategoryId":"10","SortOrder":0,"StartAd":0,"NumberOfAds":0%7d'
      )
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        let arr = [];
        // fyll på båtar
        vm.boats = data;
        // forEach...hämta detaljer
        /*data.forEach((boat) => {
          fetch(`https://www.sokbat.se/api/ad/${boat.AdId}`)
            .then((response) => {
              arr.push(response.json())
          })
        })*/
        this.calcAttributes(data);
        //vm.boats = arr;
      });
      },
      computed: {
    computed_items: function () {
      const vm = this;
      let filterType = this.selected.options.type,
        filterEngineModel = this.selected.options.engineModel,
        filterBrand = this.selected.options.brand,
        // Ranges
        filterPrice = this.selected.options.price,
        filterYear = this.selected.options.year,
        filterLength = this.selected.options.length,
        filterWidth = this.selected.options.width;
    
      return this.boats.filter(function (item) {
        let filtered = true;
    
        if (filtered) {
          // BÃ¥ttyp
          if (filterType && filterType.length > 0) {
            filtered = item.MotoBoatTypeSelectionCaption == filterType;
          }
          // Märke
          if (filterBrand && filterBrand.length > 0) {
            filtered = item.Brand == filterBrand;
          }
          // BÃ¥tmotor
          if (filterEngineModel && filterEngineModel.length > 0) {
            filtered = item.EngineModel == filterEngineModel;
          }
          // Motorår
          if (filterYear && filterYear != "") {
            filtered = item.BoatYear == filterYear;
          }
          /* Pris
          if (filterPrice && filterPrice[0] > vm.filter.options.minPrice) {
            filtered = item.Price >= filterPrice[0]
          }
          // Längd
          if (filterWidth && filterWidth[0] >= vm.filter.options.minWidth) {
            filtered = item.Width >= filterWidth[0]
          }
          if (filterLength && filterLength[0] >= vm.filter.options.minLength) {
            filtered = item.Length >= filterLength[0]
          }*/
        }
        return filtered;
      });
    }
      },
      mounted: function () {
    const vm = this;
    let i = 0;
    this.$watch('selected', function () {
      console.log(vm.computed_items);
    }, {deep:true})
      },
      methods: {
    calcAttributes(data) {
      const vm = this;
      let tmp_brands = [],
        tmp_models = [],
        tmp_yrs = [],
        tmp_width = [],
        tmp_types = [];
    
      data.forEach((item) => {
        tmp_brands.push(item.Brand);
        tmp_models.push(item.EngineModel);
        tmp_yrs.push(item.BoatYear);
        tmp_types.push(item.MotoBoatTypeSelectionCaption)
      });
    
      let maxPrice = 0,
        minPrice = 0,
        minWidth = 0,
        maxWidth = 0,
        minLength = 0,
        maxLength = 0;
      data.forEach(item => {
        if (item.Price >= maxPrice) {
          maxPrice = item.Price
        }
        if (item.Price <= maxPrice) {
          minPrice = item.Price
        }
        //
        if (item.Width >= maxWidth) {
          maxWidth = item.Width
        }
        if (item.Width <= minWidth) {
          minWidth = item.Width
        }
        //
        if (item.Length >= maxLength) {
          maxLength = item.Length
        }
        if (item.Length <= minLength) {
          minLength = item.Length
        }
      });
      // min/max bredd
      // unique's
      vm.filter.options.maxPrice = maxPrice;
      vm.filter.options.minPrice = minPrice;
      //
      vm.filter.options.maxWidth = maxWidth;
      vm.filter.options.minWidth = minWidth;
      vm.filter.options.type = Array.from(new Set(tmp_types));
      //
      vm.filter.options.maxLength = maxLength;
      vm.filter.options.minLength = minLength;
      vm.filter.options.brands = Array.from(new Set(tmp_brands))
      vm.filter.options.engineModels = Array.from(new Set(tmp_models))
      vm.filter.options.years = Array.from(new Set(tmp_yrs));
    }
      }
    });
    [v-cloak]{display:none}body{font-family:Ubuntu}.filter-box{background:#333;border-radius:5px;padding:1rem;margin:2rem}.results{padding:1rem;margin:2rem}.el-row{margin-bottom:20px}.el-row:last-child{margin-bottom:0}.el-col{border-radius:4px}.bg-purple-dark{background:#99a9bf}.bg-purple{background:#d3dce6}.bg-purple-light{background:#e5e9f2}.grid-content{border-radius:4px;min-height:36px}.row-bg{padding:10px 0;background-color:#f9fafc}.el-select{width:100%}.el-input__inner{color:#333!important}.inline>p{color:#fff;margin:0;padding:0}.boat-card{margin:10px}.time{font-size:16px;line-height:20px;color:#999}.time p{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.time p br{display:none}.bottom{margin-top:13px;line-height:12px}.button{padding:0;float:right}.image{width:100%;display:block}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}input::placeholder{color:#333!important}.el-col.el-col-8.el-col-xs-24.el-col-sm-12.el-col-md-8.el-col-lg-6{min-height:350px}.fade-enter-active,.fade-leave-active{transition:opacity .5s}.fade-enter,.fade-leave-to{opacity:0}a{text-decoration:none}
    <div id="app" v-cloak>
    
      <div class="filter-box">
    
        <el-row :gutter="20">
          <el-col :span="6">
            <el-select v-model="selected.options.brand" placeholder="Märke">
              <el-option default label="Alla" value=""></el-option>
              <el-option v-for="item in filter.options.brands" :key="item" :label="item" :value="item">
              </el-option>
            </el-select>
          </el-col>
    
          <el-col :span="12">
            <div class="inline">
              <p>Pris</p>
              <el-slider v-model="selected.options.price" range :min="filter.options.minPrice" :max="filter.options.maxPrice">
              </el-slider>
            </div>
          </el-col>
    
          <el-col :span="6">
            <el-select v-model="selected.options.engineModel" placeholder="Motormodell">
              <el-option default label="Alla" value=""></el-option>
              <el-option v-for="item in filter.options.engineModels" :key="item" :label="item" :value="item">
              </el-option>
            </el-select>
          </el-col>
    
        </el-row>
    
    
        <el-row :gutter="20">
          <el-col :span="6">
            <el-select v-model="selected.options.type" placeholder="BÃ¥ttyp">
              <el-option default label="Alla" value=""></el-option>
              <el-option v-for="item in filter.options.type" :key="item" :label="item" :value="item">
              </el-option>
            </el-select>
          </el-col>
    
          <el-col :span="6">
            <div class="inline">
              <p>Bredd</p>
              <el-slider v-model="selected.options.width" range :min="filter.options.minWidth" :max="filter.options.maxWidth">
              </el-slider>
            </div>
          </el-col>
    
          <el-col :span="6">
            <div class="inline">
              <p>Längd</p>
              <el-slider v-model="selected.options.length" range show-stops :min="filter.options.minLength" :max="filter.options.maxLength">
              </el-slider>
            </div>
          </el-col>
    
          <el-col :span="6">
            <el-select v-model="selected.options.year" placeholder="År">
              <el-option default label="Alla" value=""></el-option>
              <el-option v-for="item in filter.options.years" :key="item" :label="item" :value="item">
              </el-option>
            </el-select>
          </el-col>
    
        </el-row>
    
      </div>
    
      <div v-if="boats.length > 1" class="results">
        <el-row>
    
          <el-col v-for="(boat, i) in computed_items" :span="8" :key="i" :xs="8" :sm="8" :md="8" :lg="6">
            <transition name="fade">
              <a :href="`https://marine.local/bat/?id=${boat.AdId}`" target="_blank">
                <el-card class="boat-card" :body-style="{ padding: '8px' }" shadow="hover">
                  <img :src=`${boat.AdResourceURI}` class="image">
                  <div style="padding: 14px;">
                    <span>{{boat.AdTitle}}</span>
                    <div class="bottom clearfix">
                      <time class="time" :inner-html.prop="boat.AdIntroduction | truncate(60)"></time>
                      <el-button type="text" class="button">
                        {{boat.Price.toLocaleString('sv-SE', { style: 'currency', currency: 'SEK' })}}
                      </el-button>
                    </div>
                  </div>
                </el-card>
              </a>
            </transition>
    
          </el-col>
    
        </el-row>
      </div>
    
    </div>
    
    <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.5.17/vue.js"></script>
    <link href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" rel="stylesheet" />
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    0 回复  |  直到 4 年前
        1
  •  1
  •   jotaelesalinas    4 年前

    你已经有过滤器了 data.filter.options minLength , maxLength ,还有更多。

    this.filter.options 匹配你船上的变量,例如。 brand 而不是 brands .

    computed: {
      filtered_boats: function () {
        let filtered = this.boats;
    
        // the minimums
        let mins = {
          "minPrice": 'price',
          "minLength": 'length',
          ...
        };
        filtered = Object.keys(mins).forEach(k => if (this.filter.options[k] !== null) filtered = filtered.filter(boat => boat[mins[k]] >= this.filter.options[k]));
    
        // the maximums
        let maxs = {
          "maxPrice": 'price',
          "maxLength": 'length',
          ...
        };
        filtered = Object.keys(maxs).forEach(k => if (this.filter.options[k] !== null) filtered = filtered.filter(boat => boat[maxs[k]] <= this.filter.options[k]));
    
        // the multi-value filters
        let fields = ['brand', 'model', 'type', ...];
        filtered = fields.forEach(f => if (this.filter.options[f].length > 0) filtered = filtered.filter(boat => this.filter.options[f].indexOf(boat[f]) != -1));
    
        return filtered;
      }
    }
    

    抱歉,我无法测试代码。但我希望你能明白!