ReactJS-同位素布局-使用数据属性进行过滤/排序

问题描述

我正在尝试简化React组件中的同位素处理程序-我想创建类似于catergory [metal]或catergory [transition]的过滤器选项-以及类似于catergory [metal,transition]的组合过滤器。 / p>

此沙箱。 https://codesandbox.io/s/brave-sea-tnih7

就像filterFns [filterValue,“ param2”]-如何将2个参数推入过滤器函数-而不是固定的GreaterThan50-“ greaterThan(50)”,“ greaterThan(5)-这种动态过滤处理程序类型“

enter image description here

最新的沙箱 https://codesandbox.io/s/brave-sea-tnih7?file=/src/IstotopeWrapper.js

enter image description here

import React,{ Component } from 'react';

import Isotope from 'isotope-layout';

import Button from '@material-ui/core/Button';
import ButtonGroup from '@material-ui/core/ButtonGroup';

import GenericForm from '../GenericForm/GenericForm';

import './IsotopeHandler.scss';


class IsotopeHandler extends Component {
    constructor() {
      super();
      this.myRef = React.createRef();


      let items = [{
        "name": "Mercury","category": "transition","weight": "122","symbol": "Hg","number": 12,"custom": "a","isgas": false
      },{
        "name": "Tellurium","category": "metal","weight": "12","symbol": "Te","number": 232,"custom": "b",{
        "name": "Bismuth","category": "rock","weight": "2200.59","symbol": "Bi","number": 1666,"custom": "c",{
        "name": "Cadmium","weight": "1200","symbol": "Cd","number": 454,"custom": "d",{
        "name": "Bosim","category": "gas","weight": "100","symbol": "Gs","custom": "e","isgas": true
      },{
        "name": "xosim","symbol": "xs","number": 44,"custom": "f","isgas": true
      }]

      this.state = { sortBy: 'original-order',items: items };

      this.onFilterHandler = this.onFilterHandler.bind(this);
      this.onSortHandler = this.onSortHandler.bind(this);
    }

    onSortHandler(sortValue){
      if(sortValue){
        console.log("sortValue",sortValue);
        let bool = this.state.bool;
        let options = { sortBy: sortValue };
        
        options = Object.assign(options,{
            sortAscending: (bool = !bool),});        

        this.setState({ bool: bool });
        this.setState({ sortBy: sortValue });

        this.state.iso.arrange(options);
      }
    }

    onFilterHandler(filterName,filterField,filterValue){

        var filterFns = {
          //match
          matches: function(itemElem) {
            var values = itemElem.getAttribute('data-'+filterField);
            return values.match(filterValue);
          },//greaterThan 
          greaterThan: function(itemElem) {
            var number = itemElem.getAttribute('data-'+filterField);
            return parseInt(number,10) > filterValue;
          },//lessThan 
          lessThan: function(itemElem) {
            var number = itemElem.getAttribute('data-'+filterField);
            return parseInt(number,10) < filterValue;
          },//Between 
          between: function(itemElem) {
            var number = itemElem.getAttribute('data-'+filterField);
            return parseInt(number,10) > parseInt(filterValue.split(",")[0],10) && parseInt(number,10) < parseInt(filterValue.split(",")[1],10);
          },};

        // use matching filter function
        let val = filterFns[filterName] || filterValue;

        this.state.iso.arrange({ filter: val });
    }

    submitFilterFormHandler(data){
      console.log("data now with parent",data);

      if(data){
        //open dialog box
        //console.log("this",this);
      }
    }

    componentDidMount(){
        // init Isotope
        var iso = new Isotope(this.myRef.current,{
          itemSelector: '.grid-item',layoutMode: 'fitRows',getSortData: this.getCustomSortAttributes(this.state.items[0])
        });

        this.setState({ iso: iso });
        console.log("iso",iso);
    }

    getCustomSortAttributes(item){
      let keys = Object.keys(item);
      let dataObj = {};
      
      for (let i = 0; i < keys.length; i++) {
        var obj = {
          [keys[i]]: '[data-'+keys[i]+']'
        }
        dataObj = {...obj,...dataObj}
      }
      return dataObj;      
    }

    attributeGeneration(item){
      let keys = Object.keys(item);
      let dataObj = {};
      
      for (let i = 0; i < keys.length; i++) {
        var obj = {
          ["data-"+keys[i]]: item[keys[i]]
        }
        dataObj = {...obj,...dataObj}
      }
      return dataObj;
    }

    render() {


        var sorts = [{
          "label": "Original Order","value": "original-order"
        },{
          "label": "Name","value": "name"
        },{
          "label": "Symbol","value": "symbol"
        },{
          "label": "Number","value": "number"
        },{
          "label": "Weight","value": "weight"
        },{
          "label": "Category","value": "category"
        },{
          "label": "Custom","value": "custom"
        }]


        let filters = [{
            "label": "show all","params": {
              "filter": "showAll","field": "","value": "*"
            }
          },{
            "label": "number > 50","params": {
              "filter": "greaterThan","field": "number","value": 50
            }
          },{
            "label": "number < 350","params": {
              "filter": "lessThan","value": 350
            }
          },{
            "label": "between- number < 350 && number < 600","params": {
              "filter": "between","value": "350,600"
            }
          },{
            "label": "metal category","params": {
              "filter": "matches","field": "category","value": "metal"
            }
          },{
            "label": "metal transition","value": "transition"
            }
          },{
            "label": "metal gas and transition","value": "gas|transition"
            }
          },{
            "label": "isGas","field": "isgas","value": true
            }
          }]



        let initialFilterFormValues = {
          "manual": "type to filter"
        }

        let fieldsFilterForm = [
            {
              "type": "text","label": "Manual Entry","name": ["manual"],"options": []
            },{
              "type": "buttons","label": "Sweets2","name": ["sweets2"],"options": [
                {
                  "label": "Sherbert","value": "0"
                },{
                  "label": "Peach Jam","value": "1"
                },{
                  "label": "Almond Butter","value": "2"
                }
              ],//"validate": ["required"],}            
          ];

        let buttonsFilterForm = [
          /*{
            "label": "Submit3","variant": "contained","color": "primary","type": "submit","disabled": ["submitting"],"onClick" : null
          }*/
        ];


        return (
          <div 
            className={"isotope"}
          >

            <div className="button-group filters-button-group">
              <ButtonGroup variant="outlined" color="primary" aria-label="outlined primary button group">
              {                
                filters.map((item,j) => {
                  return(
                    <Button 
                      key={j} 
                      className="button" 
                      onClick={() => this.onFilterHandler(item.params.filter,item.params.field,item.params.value)}
                    >
                      {item.label}
                    </Button>
                  )
                })
              }
              {/*
              <Button className="button" data-filter=".alkali,.alkaline-earth">alkali and alkaline-earth</Button>
              <Button className="button" data-filter=":not(.transition)">not transition</Button>
              <Button className="button" data-filter=".metal:not(.transition)">metal but not transition</Button>
              */}
              </ButtonGroup>   
            </div>

            <div className="button-group sort-by-button-group">
              <ButtonGroup variant="outlined" color="primary" aria-label="outlined primary button group">
                {                
                  sorts.map((item,j) => {
                    return(
                      <Button 
                        key={j} 
                        className="button" 
                        onClick={() => this.onSortHandler(item.value)}
                      >
                        {item.label}
                      </Button>
                    )
                  })
                }                
              </ButtonGroup>
            </div>


            {/*
            <GenericForm 
              initialValues={initialFilterFormValues} 
              fields={fieldsFilterForm}
              buttons={buttonsFilterForm}
              submitHandler={this.submitFilterFormHandler}
            />
            */}


            <div 
              className="grid" 
              ref={this.myRef}
            >
              {
                this.state.items.map((item,j) => {
                  return(
                    <div
                      key={j} 
                      className="grid-item"
                      {...this.attributeGeneration(item)}
                    >
                      <h3>{item.name}</h3>
                      <p>{item.weight}</p>
                      <p>{item.number}</p>
                      <p>{item.symbol}</p>
                      <p>{item.category}</p>
                    </div>
                  )
                })
              }
            </div>

          </div>
        );
    }
}

export default IsotopeHandler;

解决方法

在您的应用程序中,您可以将过滤器存储在阵列中,并将过滤器阵列更新为新过滤器(单过滤器模式),也可以将新选择的过滤器推入现有过滤器列表的顶部。

在此处查看更新的codesandbox

首先,我们要在同位素中注册过滤方法:

componentDidMount() {
  // init Isotope
  var iso = new Isotope(this.myRef.current,{
    itemSelector: ".grid-item",layoutMode: "fitRows",getSortData: this.getCustomSortAttributes(this.state.items[0]),filter: this.filterData  // <- custom filter method
  });

  this.setState({ iso: iso });
  console.log("iso",iso);
}

更新了onFilterHandler,它需要3个参数

  1. addFilter:布尔值标志,指示是应添加新的过滤条件还是应删除现有的过滤条件
  2. filterCondition:字符串条件或条件数组,格式为rule|field|value
  3. type:将ANDOR终止的字符串值,以确定类型中的所有条件都应匹配还是任何单个条件都应匹配

基于areguments函数,要么添加新过滤器,要么搜索现有过滤器,然后将其从全局filters数组中删除。

getFilterObject(condition) {
  const conditionItems = condition.split("|");
  const filterName = conditionItems[0];
  const filterField = conditionItems[1];
  const filterValue = conditionItems[2];

  return {
    condition: condition,name: filterName,field: filterField,value: filterValue,filterFunc: this.filterFns[filterName]
  };
}

onFilterHandler(addFilter,filterCondition,type = "AND") {
  // use matching filter function
  // let val = filterFns[filterName] || filterValue;
  const filterObj = {
    type: type,filters: Array.isArray(filterCondition)
      ? filterCondition.map((cnd) => this.getFilterObject(cnd))
      : [this.getFilterObject(filterCondition)]
  };
  const existingFilters = this.filters.filter(
    (f) =>
      f.filters.length === filterObj.filters.length &&
      f.filters.every((f) =>
        filterObj.filters.some(
          (fObjFilter) => fObjFilter.condition === f.condition
        )
      )
  );

  if (addFilter && existingFilters.length === 0) {
    this.filters = [...this.filters,filterObj];
  } else if (!addFilter) {
    this.filters = this.filters.filter((f) => !existingFilters.includes(f));
  }

  this.state.iso.arrange();
}

新添加的filterData函数将负责根据当前过滤器列表过滤数据:

filterData(item) {
    if (this.filters.length <= 0) {
      return true;
    }

    const filterPredicate = (filterObj) => {
      return typeof filterObj.filterFunc === "function"
        ? filterObj.filterFunc(item,filterObj.field,filterObj.value)
        : filterObj.value === "*"
        ? true
        : item.classList.contains(filterObj.value);
    };

    for (let idx = 0; idx < this.filters.length; idx++) {
      const filterObj = this.filters[idx];
      const retVal =
        filterObj.type === "OR"
          ? filterObj.filters.some((fObjFilter) => filterPredicate(fObjFilter))
          : filterObj.filters.every((fObjFilter) =>
              filterPredicate(fObjFilter)
            );

      if (retVal) {
        return retVal;
      }
    }
    return false;
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...