jQuery过滤器显示数据属性任意或全部

时间:2016-11-29 11:13:40

标签: javascript jquery arrays wildcard

我有一些用户可以filter()以下div的下拉菜单。按钮引用三个单独的数据属性。单击按钮时,该值将添加到数组中,然后根据这些数组中的值过滤内容。虽然我只有两个下拉列表,但我遇到了四个场景来测试数组是否为空:如果它是空的我只是测试了data-attribute的存在,如果有一个值,那么我用它进行过滤。

通过添加第三个过滤器,我(我认为)有9个可能的场景进行测试,并想知道是否有更好的方法来做到这一点。

例如,当我只有两个过滤器时,我的数组可能看起来像:

["united-kingdom", "ireland"] //country
[] //type

var results = $(".collaborator[data-country][data-collaborator_type][data-interest]").filter(function() {
    var $this = $(this);

    if( countryArr.length !== 0 && collaborator_typeArr.length !== 0 ) {
        return countryArr.includes($this.attr("data-country")) && collaborator_typeArr.includes($this.attr("data-collaborator_type"));

    } else if( countryArr.length === 0 && collaborator_typeArr.length === 0 ) {
        return $this.attr('data-country') && $this.attr('data-collaborator_type');

    } else if( countryArr.length === 0 ) {
        console.log('any country');
        return $this.attr('data-country') && collaborator_typeArr.includes($this.attr("data-collaborator_type"));

    } else if( collaborator_typeArr.length === 0 ) {
        console.log('any type');
        return countryArr.includes($this.attr("data-country")) && $this.attr('data-collaborator_type');
    }
});

$('section.collaborator').slideUp('fast');
results.slideDown('fast');

哪种类型会返回英国和爱尔兰的结果。

我无法弄清楚是实现“任何”价值的更好方法。有没有办法可以测试'any'或通配符值,而不是检查数组是否为空。

如果我的数组看起来像

,该怎么办?
["united-kingdom", "ireland"] //country
["*"] //type

如何过滤返回所有通配符过滤器?

1 个答案:

答案 0 :(得分:0)

因为我自己的脚本风格使我能够在不必附加案例的情况下制作适度可扩展的内容 - 无论这些案例可能是简单还是复杂 - 我改变了脚本中采用的方法。

我还在HTML中添加了几个组件,但可以根据需要删除这些组件。

那就是说,我采取的方法如下,我试图在评论中充分解释代码(即使是原始代码中的那些部分,为了那些可能会查看问题和未来的答案):

// delegating the event handler to the '#network-filters'
// element, binding the anonymous function of the on()
// method to act as the 'click' event-handler for the
// click events on those elements contained within that
// match the 'a.filter' selector:
$('#network-filters').on('click', 'a.filter', function(event) {

  // preventing the default action of the <a> elements,
  // preventing the page from following the clicked links:
  event.preventDefault();

  // using the 'let' statement to declare variables, this is
  // possible in ES6-supporting browsers, for older browsers
  // you may have to use 'var' instead (in this situation
  // they're interchangeable).

  // caching the clicked element:
  let clicked = $(this),

    // finding the elements that contain the elements to
    // be filtered (I added the '#results' element):
    results = $('#results .collaborator');

  // toggling the 'toggled' class, to turn it 'on' or 'off'
  // on the clicked <a>, and removing it from the sibling
  // elements:
  clicked.toggleClass('toggled').siblings().removeClass('toggled');

  // caching '.dropdown' elements:
  let dropdowns = $('#network-filters .dropdown'),

  // declaring 'empty' variables for use within
  // the up-coming 'Array.prototype.map()' call:
    filter,
    active,
    filterValue,

  // here we convert the dropdowns jQuery collection into
  // a native JavaScript Array using get(), and then we
  // iterate over that Array using Array.prototype.map():
    selector = dropdowns.get().map(function(dropdown) {
      // 'dropdown' a reference to the current element
      // in the Array of elements over which we're
      // iterating.

      // assigning values to the declared 'empty' variables:
        // here we retrieve the value of the 'data-tax'
        // custom attribute, using the Element.dataset API:
      filter = dropdown.dataset.tax;

        // here we retrieve the element matching the supplied
        // CSS selector contained within the current
        // dropdown element, querySelector returns the first
        // or no matching elements:
      active = dropdown.querySelector('a.filter.toggled');

        // if we have an 'active' element we pass the value
        // of its 'data-filter' attribute to the variable,
        // otherwise we return false:
      filterValue = active ? active.dataset.filter : false;

      // if there was an active element:
      if (active) {
        // we construct a selector to return to the Array
        // we're creating via Array.prototype.map(), that
        // selector takes the form of:
          // 'data-' plus the attribute-value of the
          // 'data-tax' attribute, followed by either an
          // empty string (if the filterValue is exactly
          // equal to 'any') or a string containing '='
          // follwed by the found filterValue; this is
          // all then followed by a ']' character to
          // close the formed attribute-selector:
        return '[data-' + filter + (filterValue === 'any' ? '' : '=' + filterValue) + ']';

      // otherwise:
      } else {
        // we simply return false, if there was no active
        // element:
        return false;
      }

    // we then use Array.prototype.filter(Boolean) to retain
    // only those true/truthy values in the Array
    }).filter(Boolean)

    // and join all array-elements together with an empty string:
    .join('');

  // those results (the '#results .collaborator' elements) are
  // then filtered; those that do not match the created selector
  // are hidden via the slideUp() method:
  results.not(selector).slideUp();

  // then we filter the results array to find those that
  // are hidden (.not(':visible') - using the ':visible'
  // jQuery/Sizzle custom selector) which match the
  // formed selector and apply slideDown() to those
  // elements; this is simply to avoid sliding elements
  // both up and down if they're already visible:
  results.not(':visible').filter(selector).slideDown();

  // here we use a comparison to discover whether or not
  // we have any results; if the number of results elements
  // filtered by the selector is greater than 0, we return
  // true (because we have found some results), otherwise
  // we return false (because there were no matching results):
  let resultsAvailable = results.filter(selector).length > 0;

  // here we find the element (added by me to your HTML) which
  // conveys the 'result-state', and toggle the 'noResult'
  // class using the switch, in which we invert the
  // resultsAvailble variable, so that the class is added if
  // there are no results available, and removed if there are
  // results available (its default state is to be hidden,
  // and shown only if there are no results, this is in the CSS):
  $('#results .resultState').toggleClass('noResult', !resultsAvailable);

});

以上JavaScript与以下HTML结合使用:

<div id="network-filters">
  <div class="dropdown" data-tax="country">
    <div class="dropdown-content">
      <a class="filter all" data-filter="any">Show All</a>
      <a class="filter" data-filter="ireland">Ireland</a>
      <a class="filter" data-filter="united-kingdom">United Kingdom</a>

      <!-- the following two <a> elements are added to show how
           easily this approach can be extended; note that there
           is no matching element for the 'Scotland' <a>, to
           demonstrate that the script still works despite that -->
      <a class="filter" data-filter="wales">Wales</a>
      <a class="filter" data-filter="scotland">Scotland</a>
    </div>
  </div>
  <div class="dropdown" data-tax="collaborator">
    <div class="dropdown-content">
      <a class="filter all" data-filter="any">Show All</a>
      <a class="filter" data-filter="artist">Artist</a>
      <a class="filter" data-filter="partner">Partner</a>
    </div>
  </div>
</div>

<!-- the '#results' element was added to logically group the
     elements to be searched together -->
<div id="results">

  <!-- the 'resultState' element was added to visibly inform
       the user that the search was conducted and the lack of
       results is deliberate, rather than the result of a
       broken script -->
  <div class="resultState">No results available for that choice.</div>
  <div class="collaborator" data-country="ireland" data-collaborator="artist">
    <ul>
      <li>country = ireland</li>
      <li>type = artist</li>
    </ul>
  </div>
  <div class="collaborator" data-country="united-kingdom" data-collaborator="partner">
    <ul>
      <li>country = united-kingdom</li>
      <li>type = partner</li>
    </ul>
  </div>

  <!-- the following element was effectively cloned 
       from the same format as the other elements, 
       and dropped in justas a demonstration of how 
       easily this approach can be extended -->
  <div class="collaborator" data-country="wales" data-collaborator="partner">
    <ul>
      <li>country = wales</li>
      <li>type = partner</li>
    </ul>
  </div>
</div>

&#13;
&#13;
$('#network-filters').on('click', 'a.filter', function(event) {
  event.preventDefault();

  let clicked = $(this),
    results = $('#results .collaborator');

  clicked.toggleClass('toggled').siblings().removeClass('toggled');

  let dropdowns = $('#network-filters .dropdown'),
    filter,
    active,
    filterValue,
    selector = dropdowns.get().map(function(dropdown) {
      filter = dropdown.dataset.tax;
      active = dropdown.querySelector('a.filter.toggled');
      filterValue = active ? active.dataset.filter : false;

      if (active) {
        return '[data-' + filter + (filterValue === 'any' ? '' : '=' + filterValue) + ']';
      } else {
        return false;
      }
    }).filter(Boolean).join('');

  results.not(selector).slideUp();
  results.not(':visible').filter(selector).slideDown();

  let resultsAvailable = results.filter(selector).length > 0;

  $('#results .resultState').toggleClass('noResult', !resultsAvailable);

});
&#13;
/* SCSS from JS Fiddle demo (https://jsfiddle.net/davidThomas/5c08shbn/1/)
compiled to CSS via 'http://www.sassmeister.com/' */

.dropdown {
  margin-bottom: 10px;
}
.dropdown a {
  display: inline-block;
  cursor: pointer;
  border: 1px solid grey;
  margin-bottom: 4px;
  padding: 4px 6px;
}
.dropdown a:hover {
  background-color: grey;
}
.dropdown a.toggled {
  /* I just prefer the brighter colour */
  background-color: limegreen;
}
.collaborator {
  background-color: red;
  border: 1px solid red;
  margin-bottom: 10px;
  padding: 4px 6px;
  color: white;
}
.resultState {
  height: 2em;
  line-height: 2em;
  opacity: 0;
  transition: all 0.3s linear;
}
.resultState.noResult {
  opacity: 1;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="network-filters">
  <div class="dropdown" data-tax="country">
    <div class="dropdown-content">
      <a class="filter all" data-filter="any">Show All</a>
      <a class="filter" data-filter="ireland">Ireland</a>
      <a class="filter" data-filter="united-kingdom">United Kingdom</a>
      <a class="filter" data-filter="wales">Wales</a>
      <a class="filter" data-filter="scotland">Scotland</a>
    </div>
  </div>
  <div class="dropdown" data-tax="collaborator">
    <div class="dropdown-content">
      <a class="filter all" data-filter="any">Show All</a>
      <a class="filter" data-filter="artist">Artist</a>
      <a class="filter" data-filter="partner">Partner</a>
    </div>
  </div>
</div>
<div id="results">
  <div class="resultState">No results available for that choice.</div>
  <div class="collaborator" data-country="ireland" data-collaborator="artist">
    <ul>
      <li>country = ireland</li>
      <li>type = artist</li>
    </ul>
  </div>
  <div class="collaborator" data-country="united-kingdom" data-collaborator="partner">
    <ul>
      <li>country = united-kingdom</li>
      <li>type = partner</li>
    </ul>
  </div>
  <div class="collaborator" data-country="wales" data-collaborator="partner">
    <ul>
      <li>country = wales</li>
      <li>type = partner</li>
    </ul>
  </div>
</div>
&#13;
&#13;
&#13;

JS Fiddle demo

参考文献: