【问题标题】:Dynamically Filter an Array of Objects in Vue.js在 Vue.js 中动态过滤对象数组
【发布时间】:2018-05-01 10:45:11
【问题描述】:

我有一个 Vue.js 应用程序。在这个应用程序中,我试图将过滤器值动态地应用于对象的Array。 Array 中的每个对象都有字段。我正在尝试按字段值过滤这些对象。每个字段可以被多个值过滤。

此时,我一直未能弄清楚如何进行此过滤。我尝试过使用 JavaScript 内置的 filter 函数。但是,这总是为我返回一个空的结果集。我整理了这个Fiddle,其中包括以下代码:

new Vue({
  el: '#app',
  data: {
    currentFilterProperty: '',
    currentFilterValue: '',

    cols: [
      { title: 'Name', prop:'name' },
      { title: 'Age', prop:'age' },
      { title: 'Birthday', prop:'birthday' },      
    ],

    dataFilters: [],
    data: [
      { name:'Patricia Miller', age:69, birthday:'04-15-1948' },
      { name:'Bill Baggett', age:62, birthday:'05-07-1955' },      
      { name:'Maxine Thies', age:21, birthday:'11-28-1995' },      
      { name:'Alison Battle', age:65, birthday:'08-07-1952' },      
      { name:'Dick Triplett', age:25, birthday:'08-27-1982' } 
    ]
  },

  methods: {
    addFilter: function() {
      var f = this.dataFilters[this.currentFilterProperty];
      if (!f) {
        this.dataFilters = {};
        this.dataFilters[this.currentFilterProperty] = [ this.currentFilterValue ];
      } else {
        this.dataFilters[this.currentFilterProperty].push(this.currentFilterValue);
      }

      // How to apply filter?
    }
  }
})

我不确定如何将过滤器应用于data 对象。

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    完整的解决方案。最佳测试:添加过滤器 Age 62,然后是生日 04-15-1948,然后在 Name Patricia 中添加“tri”。

    new Vue({
      el: '#app',
      data: {
        filteredProperty: 'name',
        query: '',
        activeFilters: [],
        data: [
          {name: 'Patricia Miller', age: 62, birthday: '04-15-1948'},
          {name: 'Bill Baggett', age:62, birthday: '04-15-1948' },
          {name:'Maxine Thies', age:62, birthday:'11-28-1948'},
          {name:'Alison Battle', age:65, birthday:'08-07-1952'},      
          {name:'Dick Triplett', age:25, birthday:'08-27-1982'}
        ]
      },
      computed: {
        filtered () {
          var filtered = this.data
          this.activeFilters.forEach(filter => {
            filtered = filtered.filter(record => {
              return filter.name === 'name'
                ? new RegExp(filter.value, 'i').test(record[filter.name])
                : record[filter.name] == filter.value
            })
          })
          return filtered
        }
      },
      methods: {
        addFilter () {
          this.activeFilters.push({
            name: this.filteredProperty,
            value: this.query
          })
          this.query = ''
        },
        removeFilter (idx) {
          this.activeFilters.splice(idx, 1)
        }
      }
    })
    <div id="app">
      <div>
        <select v-model="filteredProperty">
          <option value="name">Name</option>
          <option value="age">Age</option>
          <option value="birthday">Birthdate</option>
        </select>
        <input placeholder="filter value" v-model="query">    
        <button @click="addFilter">add filter</button>
      </div>
      <hr>
      <table v-if="activeFilters.length">
        <tr style="width: 100px">
          <th colspan="3">Filters in use:</th>
        </tr>
        <tr v-for="(filter, index) in activeFilters" :key="index">
          <td>{{ _.capitalize(filter.name) }}:</td>
          <td>{{ filter.value }}</td>
          <td style="padding-left: 10px;">
            <a href="#" @click.prevented=removeFilter(index)>
              remove
            </a>
          </td>
        </tr>
      </table>
      <hr v-if="activeFilters.length">
      <table>
        <tbody>
          <tr v-for="(record, index) in filtered" :key="index">
            <td style="padding-right:18px;">{{ record.name }}</td>
            <td style="padding-right:18px;">{{ record.age }}</td>
            <td>{{ record.birthday }}</td>
          </tr>
        </tbody>
      </table>  
    </div>
    
    <script src="https://unpkg.com/vue"></script>
    <script src="https://unpkg.com/lodash"></script>

    【讨论】:

      【解决方案2】:

      看看下面的代码。将您的方法更改为计算属性,然后过滤器可以自动发生而无需按下按钮。小提琴总是按名称过滤,因此您需要进行一些调整以适用于所有过滤条件,但它应该让您朝着正确的方向前进。

      new Vue({
        el: '#app',
        data: {
          currentFilterProperty: '',
          currentFilterValue: '',  
          cols: [
            { title: 'Name', prop:'name' },
            { title: 'Age', prop:'age' },
            { title: 'Birthday', prop:'birthday' }  
          ],
          data: [
            { name:'Patricia Miller', age:69, birthday:'04-15-1948' },
            { name:'Bill Baggett', age:62, birthday:'05-07-1955' },      
            { name:'Maxine Thies', age:21, birthday:'11-28-1995' },      
            { name:'Alison Battle', age:65, birthday:'08-07-1952' },      
            { name:'Dick Triplett', age:25, birthday:'08-27-1982' } 
          ]
        },
        computed:{
        	filteredData(){
          	var self = this;
              // Add condition for currentFilterProperty == 'Name'
          	if(this.currentFilterValue != undefined && this.currentFilterValue != ''){
            	return this.data.filter(function(d){
              	//alert(d.name + " " + this.currentFilterValue);
            		return d.name.indexOf(self.currentFilterValue) != -1;
            	});          
            }
            // else if(currentFilterProperty == 'Date'){
            // return this.data.filter(function(d){
              	
            		//return d.birthday.indexOf(self.currentFilterValue) != -1;
            //	});
            else{
            	return this.data;
            }    	
          }
        }
      })
      <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.4/vue.min.js"></script>
      
      <div id="app">
        <div>
          <select v-model="currentFilterProperty">
            <option v-for="c in cols" :value="c.prop">{{c.title}}</option>
          </select>
          
          <input placeholder="filter value" v-model="currentFilterValue" />
        </div>
        <hr />
      
        <table>
          <tbody>
            <tr v-for="(record, index) in filteredData">
              <td style="padding-right:18px;">{{ record.name }}</td>
              <td style="padding-right:18px;">{{ record.age }}</td>
              <td>{{ record.birthday }}</td>
            </tr>
          </tbody>
        </table>  
      </div>

      【讨论】:

      • @user2486 我在帖子中提到该代码仅用于过滤名称字段。您必须向 if/thens 添加一些条件以说明 currentFilterProperty。如果有机会,我会回到代码上,但我只是想让你走上正确的轨道,让你完成代码。您将需要类似if(currentFilterProperty == 'Name') then ... else if(currentFilterProperty == 'Date') then ...
      • @user2486 我添加了一些注释代码,让您了解需要做什么。注释代码未经测试。
      【解决方案3】:

      这是工作解决方案通过检查captaining 条件

      new Vue({
        el: '#app',
        data: {
          currentFilterProperty: 'name',
          currentFilterValue: '',
          filteredData:[],
          cols: [
            { title: 'Name', prop:'name' },
            { title: 'Age', prop:'age' },
            { title: 'Birthday', prop:'birthday' },      
          ],
      
          dataFilters: [],
          addFilters:[],
          data: [
            { name:'Patricia Miller', age:69, birthday:'04-15-1948' },
            { name:'Bill Baggett', age:62, birthday:'05-07-1955' },      
            { name:'Maxine Thies', age:21, birthday:'11-28-1995' },      
            { name:'Alison Battle', age:65, birthday:'08-07-1952' },      
            { name:'Dick Triplett', age:25, birthday:'08-27-1982' } 
          ]
        },
        
        methods: {
          addFilter: function() {
           if(!this.currentFilterValue){
            return false;
           }
            var obj = {};
            this.addFilters.push({name:this.currentFilterProperty,value:this.currentFilterValue});
            this.currentFilterValue = "";
          	var vm = this;
            this.dataFilters = this.data
            //var temp = [];
            for(var i in vm.addFilters){
              this.dataFilters = this.dataFilters.filter(function(a,b){
              return ((a[vm.addFilters[i].name]).toString().toLowerCase()).indexOf((vm.addFilters[i].value).toString().toLowerCase()) !== -1;
              });
            }
            // How to apply filter?
          }
        },
        mounted(){
          this.dataFilters = this.data;
        }
      })
      <script src="https://unpkg.com/vue"></script>
      
      <div id="app">
        <div>
          <select v-model="currentFilterProperty">
            <option value="name">Name</option>
            <option value="age">Age</option>
            <option value="birthday">Birthdate</option>
          </select>
          <input placeholder="filter value" v-model="currentFilterValue" />
          
          <button v-on:click="addFilter">
          add filter
          </button>
        </div>
        <div v-for="(filter,index) in addFilters">{{filter.name}} : {{filter.value}}</div>
        <hr />
      
        <table>
          <tbody>
            <tr v-for="(record, index) in dataFilters">
              <td style="padding-right:18px;">{{ record.name }}</td>
              <td style="padding-right:18px;">{{ record.age }}</td>
              <td>{{ record.birthday }}</td>
            </tr>
          </tbody>
        </table>  
      </div>

      【讨论】:

      • 只过滤,不添加过滤器。
      • @是你的权利:它只是过滤不添加过滤器
      • @Waldemarlce :还添加了过滤器,但您的回答很好,删除
      猜你喜欢
      • 2020-06-24
      • 2022-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-30
      • 1970-01-01
      • 2018-04-19
      • 1970-01-01
      相关资源
      最近更新 更多