Select2 - 按查询排序结果

Posted

技术标签:

【中文标题】Select2 - 按查询排序结果【英文标题】:Select2 - Sorting results by query 【发布时间】:2015-11-06 14:20:15 【问题描述】:

我使用的是 Select2 版本 4.0.0。

如果我的结果包含多个单词,并且用户输入了其中一个单词,我 想要显示按输入单词在结果中的位置排序的结果。

比如一个用户输入“apple”,我的结果是:

    “香蕉橙苹果” “香蕉苹果橙” “苹果香蕉橙”

那么“apple banana orange”应该首先出现在 select2 结果列表中,因为那是“apple”在结果中出现最早的结果。我不太关心过去的订购。

我应该覆盖或配置什么来获得这样的东西?似乎matcher 没有 处理排序,sorter 不包含查询数据。

【问题讨论】:

在原始列表中排列元素可能更容易。并且大概它们将在过滤期间显示为已排序。 我不明白你的评论。在用户开始搜索之前,我怎么知道如何排列列表? 我的意思是。如果您最初按字母顺序对列表进行排序,您会在搜索过程中收到哪个排序列表? 搜索时的排序默认是字母顺序。这就是我想要改变的。 我认为这并不完全清楚,如果术语以您搜索的内容开头,您是否希望结果首先出现? 【参考方案1】:

您可以通过使用 select2-search__field 类标识 Select2 生成的输入框的值来获取搜索查询。这可能会跨越版本,但由于它们不提供获取查询的钩子,因此需要某种 hack。您可以submit an issue 让他们添加对在排序期间访问查询的支持,特别是因为它看起来在 Select2 3.5.2 中是可能的。

$('#fruit').select2(
  width: '200px',
  sorter: function(results) 
    var query = $('.select2-search__field').val().toLowerCase();
    return results.sort(function(a, b) 
      return a.text.toLowerCase().indexOf(query) -
        b.text.toLowerCase().indexOf(query);
    );
  
);
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet" />

<select id="fruit">
  <option>Banana Orange Apple</option>
  <option>Banana Apple Orange</option>
  <option>Apple Banana Orange</option>
  <option>Achocha Apple Apricot</option>
  <option>Durian Mango Papaya</option>
  <option>Papaya</option>
  <option>Tomato Papaya</option>
  <option>Durian Tomato Papaya</option>
</select>

【讨论】:

请注意,您几乎可以保证text 将包含搜索词。唯一的例外是如果您使用的是自定义 matcher,此时您很可能知道例外是什么。 感谢@KevinBrown 的评论。我相信text 将包含搜索词,因此我相应地简化了代码。 谢谢,这几乎可以工作,但它似乎并没有对整个列表进行排序。就像,如果我有多个结果,其中“apple”是第一个单词,它会将一个放在顶部,然后将其他结果未排序在不相关的结果下方。我现在正在尝试@KevinBrown 的方法。 @nnyby 呵呵。你只想匹配整个单词吗?例如,如果您正在搜索 apple 并且有两个结果:banana orange applehorseapple tomato,您是否希望 banana orange apple 先出现? @heenenee 现在可以完美运行了,谢谢!我实际上是在尝试 Kevin Brown 的方法,它给了我相同的结果,即使我添加了一个不区分大小写的 hack,所以我正要假设你的方法会有相同的行为。非常感谢......我已经搞砸了这么久。【参考方案2】:

这里的问题是,Select2 在 4.0.0 版本中,将结果的查询与结果的显示分开了。因此,您通常用于对结果进行排序的 sorter 选项不会传递到所做的查询(包括搜索词)中。

因此,您需要找到一种方法来缓存所做的查询,以便在排序时使用它。在我关于underlining the search term in results 的回答中,我通过loading 模板方法缓存查询,每当进行搜索时都会触发该方法。同样的方法也可以在这里使用。

var query = ;

$element.select2(
  language: 
    searching: function (params) 
      // Intercept the query as it is happening
      query = params;

      // Change this to be appropriate for your application
      return 'Searching…';
    
  
);

所以现在您可以构建一个自定义的sorter 方法,该方法使用保存的query(并使用query.term 作为搜索词)。对于我的示例排序方法,我使用文本中搜索结果对结果进行排序的位置。这可能与您正在寻找的类似,但这是一种非常暴力的方法。

function sortBySearchTerm (results) 
  // Don't alter the results being passed in, make a copy
  var sorted = results.slice(0);

  // Array.sort is an in-place sort
  sorted.sort(function (first, second) 
    query.term = query.term || "";

    var firstPosition = first.text.toUpperCase().indexOf(
      query.term.toUpperCase()
    );
    var secondPosition = second.text.toUpperCase().indexOf(
      query.term.toUpperCase()
    );

    return firstPosition - secondPosition;
  );

  return sorted;
;

这将按照您希望的方式对事物进行排序。您可以在下面找到将所有部分连接在一起的完整示例。它使用了您在问题中提到的三个示例选项。

var query = ;
var $element = $('select');

function sortBySearchTerm (results) 
  // Don't alter the results being passed in, make a copy
  var sorted = results.slice(0);
  
  // Array.sort is an in-place sort
  sorted.sort(function (first, second) 
    query.term = query.term || "";

    var firstPosition = first.text.toUpperCase().indexOf(
      query.term.toUpperCase()
    );
    var secondPosition = second.text.toUpperCase().indexOf(
      query.term.toUpperCase()
    );
    
    return firstPosition - secondPosition;
  );
  
  return sorted;
;

$element.select2(
  sorter: sortBySearchTerm,
  language: 
    searching: function (params) 
      // Intercept the query as it is happening
      query = params;

      // Change this to be appropriate for your application
      return 'Searching…';
    
  
);
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.css" rel="stylesheet"/>

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.js"></script>

<select style="width: 50%">
  <option>banana orange apple</option>
  <option>banana apple orange</option>
  <option>apple banana orange</option>
</select>

【讨论】:

【参考方案3】:

不需要保持期限:

$element.select2(
    sorter: function (data) 
        if(data && data.length>1 && data[0].rank)
            data.sort(function(a,b) return (a.rank > b.rank) ? -1 : ((b.rank > a.rank) ? 1 : 0); );
        
        return data;
    
    ,
    matcher:function(params, data) 
        // If there are no search terms, return all of the data
        if ($.trim(params.term) === '') 
          return data;
        

        // Do not display the item if there is no 'text' property
        if (typeof data.text === 'undefined') 
          return null;
        

        // `params.term` should be the term that is used for searching
        // `data.text` is the text that is displayed for the data object
        var idx = data.text.toLowerCase().indexOf(params.term.toLowerCase());
        if (idx > -1) 
          var modifiedData = $.extend(
            // `rank` is higher when match is more similar. If equal rank = 1
              'rank':(params.term.length / data.text.length)+ (data.text.length-params.term.length-idx)/(3*data.text.length)
          , data, true);

          // You can return modified objects from here
          // This includes matching the `children` how you want in nested data sets
          return modifiedData;
        

        // Return `null` if the term should not be displayed
        return null;
    

)

【讨论】:

以上是关于Select2 - 按查询排序结果的主要内容,如果未能解决你的问题,请参考以下文章

Select2 Ajax 不根据查询过滤结果

select2 使用查询词过滤本地 JSON 数据结果

Select2 Ajax 不匹配结果

Select2 按选项值自动完成

Select2 ajax不显示结果

当搜索没有返回结果时,Select2 过滤器值消失