Vue JS 基于复选框数组过滤结果

Posted

技术标签:

【中文标题】Vue JS 基于复选框数组过滤结果【英文标题】:Vue JS filter results based on checkbox array 【发布时间】:2019-03-01 10:11:28 【问题描述】:

我已经构建了一个 Vue JS 搜索组件来搜索和过滤属性网站的属性列表。搜索组件列在每个页面上,因此对我来说,使用 URL 搜索查询将我带到主属性页面然后使用类似 this.$route.query.search 的内容从我的查询中获取值并存储在变量中是有意义的。

属性数据来自一个 JSON 文件,基本上如下所示:


  "data": [
    
      "id": 12,
      "sold": false,
      "isFeatured": true,
      "slug": "green-park-talbot-green-cf72-8rb",
      "address": "Green Park, Talbot Green CF72 8RB",
      "county": "Rhondda Cynon Taf",
      "price": "695000",
      "features": ["Modern fitted kitchen", "Integrated appliances", "Front and rear gardens"],
      "type": "Semi-Detached",
      "bedrooms": "3"
    

我的搜索查询是这样的:

/properties/?search=Address%20Here&type=Apartment&bedrooms=2&county=Maesteg

然后会过滤每一件事。

它的工作原理非常简单,在我的数据对象中,我有我的变量,它们获取每个查询并将它们存储如下:

data () 
    return 
      searchAddress: this.$route.query.search,
      searchType: this.$route.query.type,
      searchBedrooms: this.$route.query.bedrooms,
      searchCounty: this.$route.query.county
    

然后我在计算区域内有一个名为 filteredProperties 的过滤器,它过滤掉v-for 内的属性,这里不需要显示:

computed: 
    filteredProperties: function()
      return this.properties.filter((property) => 
        return property.address.match(this.searchAddress) && property.type.match(this.searchType) && property.bedrooms.match(this.searchBedrooms) && property.county.match(this.searchCounty)
      );
    
  

现在这完全可以正常工作...但是我现在需要将其修改为而不是使用<select> 下拉列表,这是您当前选择卧室数量的方式,或者属性类型等,我现在需要用复选框替换属性类型 <select> 下拉列表,以便用户可以选择多个属性类型并将其作为数组添加到 URL 中。

我不太确定如何修改我的过滤器的这一部分,以便能够查找多种属性类型:

property.type.match(this.searchType)

非常感谢

更新

我最近尝试使用以下内容更新我的计算过滤器:

computed: 
    filteredProperties: function()
      return this.properties.filter((property) => 

        return property.address.match(this.searchAddress) &&
        this.searchAddress.some(function(val)
          return property.search.match(val)
        ) &&

        property.type.match(this.searchType) &&
        this.searchType.some(function(val)
          return property.type.match(val)
        ) &&

        property.bedrooms.match(this.searchBedrooms) &&
        this.searchBedrooms.some(function(val)
          return property.bedrooms.match(val)
        ) &&

        property.county.match(this.searchCounty) &&
        this.searchCounty.some(function(val)
          return property.county.match(val)
        )

      );
    
  

我需要使用和不使用 URL 查询的搜索。

还尝试了 if/else 语句:

computed: 
    filteredProperties: function()
      return this.properties.filter((property) => 
        return property.address.match(this.searchAddress) &&

        if (this.searchType.length > 1) 
          this.searchType.some(function(val)
            return property.type.match(val)
          )
         else 
          property.type.match(this.searchType)
         &&

        property.bedrooms.match(this.searchBedrooms) &&
        property.county.match(this.searchCounty)
      );
    
  

更新

我通过执行以下操作使其正常工作:

computed: 
    filteredProperties: function()
      return this.properties.filter((property) => 

        let searchTypeMatch;

        if (typeof this.searchType === "object") 
          searchTypeMatch = this.searchType.some(function(val)
            return property.type.match(val)
          )
         else 
          searchTypeMatch = property.type.match(this.searchType)
        

      return property.address.match(this.searchAddress) &&
        searchTypeMatch &&
        property.bedrooms.match(this.searchBedrooms) &&
        property.county.match(this.searchCounty)
      );
    
  

【问题讨论】:

您好,只是好奇您为什么使用match(...) 来查看给定地址是否包含在您的数据集中?此外,在您将其更改为复选框后,您可以保证您将在查询参数中获得一个数组。如果是,那么使用 Array.prototype 的.some(...) 进行修改将非常精简。 我可以将那个特定的.match() 更改为.some() 吗?还有哪些其他选择? 【参考方案1】:

我没有在 Vue 应用程序中使用过路由,但要使以下工作正常运行,您必须确保 this.$route.query.search(和其他路由属性)是 [](s)。

return this.searchAddress.some(function(val) 
    return property.address.match(val)
) && 
this.searchType.some(function(val)
    return property.type.match(val)
) && ...

让我知道这是否适合您。

重新编辑

您好,请将计算属性更改为以下

computed: 
    filteredProperties: function () 
        let self = this
        let routeConstraints = ['search', 'type', 'bedrooms', 'county'].filter(function (val) 
            return self.$route.query[val] !== undefined
        )
        if (routeConstraints.length === 0) 
            return self.properties
         else 
            return routeConstraints.reduce(function (acc, val) 
                return acc.filter(function (property) 
                    //basically I am checking if there is some value in the query parameter that matches properties.
                    if (self.$route.query[val] !== undefined) 
                        //check if the route parameter is an array (object)
                        if (typeof this.searchType === "object") 
                            self.$route.query[val] = [self.$route.query[val]]
                        
                    
                    return self.$route.query[val].some(function (item) 
                        //changed the matching condition to indexOf
                        return property[val].match(item).length > 0
                    )
                )
            , self.properties)
        
    

基本上,

    我正在尝试检查您的复选框选择中设置了哪些路线值 使用它来过滤属性数组。 如果没有设置,则返回所有属性。

希望这可行。

【讨论】:

我觉得这行不通,我试试.some() 这使用.some(..)。请问为什么这行不通? 如果我将property.type.match(this.searchType) 更改为property.type.some(this.searchType),它不起作用。我也尝试使用你的代码,这也不起作用:/ 嗨,感谢您的检查。请打印Array. isArray( this.searchType) 并检查是否是truetypeof this.searchType。谢谢。 好的,更新...我现在可以使用它了,它返回 true 并进行了一些修改,但是,如果数组中只有一项(例如:一种属性类型) 而不是倍数,它给了我一个错误:_this.searchType.some is not a function 但与多个一起工作正常吗?【参考方案2】:

您必须使用 JSON 作为查询参数才能序列化/反序列化数组。

data () 
    return 
      searchAddress: this.$route.query.search ? JSON.parse(this.$route.query.search) : [],
      searchType: this.$route.query.type ? JSON.parse(this.$route.query.type) : [],
      searchBedrooms: this.$route.query.bedrooms ? JSON.parse(this.$route.query.bedrooms) : [],
      searchCounty: this.$route.query.county ? JSON.parse(this.$route.query.county) : []
    

computed: 
    filteredProperties: function()
    
      return this.properties.filter((property) => 
      
        return (this.searchAddress.length ? this.searchAddress.some((address) =>
        
          return property.address.match(address);
        ) : true) && (this.searchType.length ? this.searchType.some((type) =>
        
          return property.type.match(type);
        ) : true) && (this.searchBedrooms.length ? this.searchBedrooms.some((bedrooms) =>
        
          return property.bedrooms.match(bedrooms);
        ) : true) && (this.searchCounty.length ? this.searchCounty.some((county) =>
        
          return property.county.match(county);
        ) : true)
      );
    
  

然后你像这样发送查询参数

this.$router.push("/search?search=" + JSON.stringify(searchArray) 
  + "&type=" + JSON.stringify(typeArray)
  + "&bedrooms=" + JSON.stringify(bedroomsArray)
  + "&county=" + JSON.stringify(countyArray)
);

【讨论】:

我刚试过这个,我得到:Unexpected token S in JSON at position 0 尝试搜索时 可能 JSON.parse() 的参数不是由 JSON.stringify() 生成的 - 你必须先序列化你的数组,然后才能反序列化它们。 this.$router.push("/search?search="+JSON.stringify(searchArray)+"&type="+JSON.stringify(typeArray)+"&bedrooms="+JSON.stringify(bedroomsArray)+"&county="+JSON.stringify(countyArray)); 这听起来很酷,但它是一个通用的<form> 元素,带有一个指向/properties 的操作按钮,这是我的页面,而不是/search。此外,看起来我必须将该代码绑定到点击事件中?那么如果他们只是按回车呢?我正在使用获取请求。 /search 还是/properties 无关紧要。您应该绑定到表单本身上的submit 事件(它将捕获 Enter) - 然后准备正确的 URL,将 form.action 设置为此 URL,然后将 return true

以上是关于Vue JS 基于复选框数组过滤结果的主要内容,如果未能解决你的问题,请参考以下文章

Javascript - 如何在 Vue.js 中使用多个复选框进行过滤?

Laravel 复选框过滤器 ajax

在Vue js中将复选框选择的值分组到数组中

通过复选框过滤对象数组

在循环中渲染复选框并在 Vue JS 中绑定它们的值

父更新时VUE Js子不更新