如何在没有ajax的select2 4.0中启用无限滚动

我正在使用带有自定义数据适配器的select2 。 提供给select2所有数据都是在网页中本地生成的(因此不需要使用ajax)。 由于query方法可以生成很多结果(约5k),打开选择框的速度相当慢。

作为补救措施,我想使用无限滚动。 自定义数据适配器的文档说, query方法应该与term一起接收page参数:

@param params.page应加载的特定页面。 这通常在使用远程数据集时提供,远程数据集依靠分页来确定应显示哪些对象。

但事实并非如此:只有term存在。 我试图返回more: truemore: 1000 ,但这没有帮助。 我想这是因为,默认情况下, 如果启用了ajax,则启用无限滚动 。

我猜测启用无限滚动将涉及使用amd.require ,但我不确定该怎么做。 我试过这段代码:

 $.fn.select2.amd.require( ["select2/utils", "select2/dropdown/infiniteScroll"], (Utils, InfiniteScroll) => input.data("select2").options.options.resultsAdapter = Utils.Decorate(input.data("select2").options.options.resultsAdapter, InfiniteScroll) ) 

这是咖啡脚本,但我希望它对每个人都是可读的。 input是包含select框的DOM元素 – 我之前做过input.select2( //options )

我的问题基本上是,如何在没有ajax情况下启用无限滚动?

如果启用了ajax ,则Select2将仅启用无限滚动。 幸运的是,我们可以启用它并仍然使用我们自己的适配器。 因此将空对象放入ajax选项就可以了。

 $("select").select2({ ajax: {}, dataAdapter: CustomData }); 

接下来,定义您自己的数据适配器。 在其中,inn querypagination信息推送到回调中。

  CustomData.prototype.query = function (params, callback) { if (!("page" in params)) { params.page = 1; } var data = {}; # you probably want to do some filtering, basing on params.term data.results = items.slice((params.page - 1) * pageSize, params.page * pageSize); data.pagination = {}; data.pagination.more = params.page * pageSize < items.length; callback(data); }; 

这是一个完整的小提琴

我觉得上面的答案需要更好的示范。 Select2 4.0.0 引入了自定义适配器的function 。 使用ajax: {}技巧,我创建了一个直接使用本地JSON的自定义dataAdapter jsonAdapter 。 另请注意,使用大型JSON字符串,Select2 4.0.0版本的性能令人印象深刻。 我使用在线JSON生成器并创建了10,000个名称作为测试数据。 但是,这个例子非常混乱 。 虽然这有效,但我希望有更好的方法。

在这里看到完整的小提琴: http : //jsfiddle.net/a8La61rL/

  $.fn.select2.amd.define('select2/data/customAdapter', ['select2/data/array', 'select2/utils'], function (ArrayData, Utils) { function CustomDataAdapter($element, options) { CustomDataAdapter.__super__.constructor.call(this, $element, options); } Utils.Extend(CustomDataAdapter, ArrayData); CustomDataAdapter.prototype.current = function (callback) { var found = [], findValue = null, initialValue = this.options.options.initialValue, selectedValue = this.$element.val(), jsonData = this.options.options.jsonData, jsonMap = this.options.options.jsonMap; if (initialValue !== null){ findValue = initialValue; this.options.options.initialValue = null; // <-- set null after initialized } else if (selectedValue !== null){ findValue = selectedValue; } if(!this.$element.prop('multiple')){ findValue = [findValue]; this.$element.html(); // <-- if I do this for multiple then it breaks } // Query value(s) for (var v = 0; v < findValue.length; v++) { for (var i = 0, len = jsonData.length; i < len; i++) { if (findValue[v] == jsonData[i][jsonMap.id]){ found.push({id: jsonData[i][jsonMap.id], text: jsonData[i][jsonMap.text]}); if(this.$element.find("option[value='" + findValue[v] + "']").length == 0) { this.$element.append(new Option(jsonData[i][jsonMap.text], jsonData[i][jsonMap.id])); } break; } } } // Set found matches as selected this.$element.find("option").prop("selected", false).removeAttr("selected"); for (var v = 0; v < found.length; v++) { this.$element.find("option[value='" + found[v].id + "']").prop("selected", true).attr("selected","selected"); } // If nothing was found, then set to top option (for single select) if (!found.length && !this.$element.prop('multiple')) { // default to top option found.push({id: jsonData[0][jsonMap.id], text: jsonData[0][jsonMap.text]}); this.$element.html(new Option(jsonData[0][jsonMap.text], jsonData[0][jsonMap.id], true, true)); } callback(found); }; CustomDataAdapter.prototype.query = function (params, callback) { if (!("page" in params)) { params.page = 1; } var jsonData = this.options.options.jsonData, pageSize = this.options.options.pageSize, jsonMap = this.options.options.jsonMap; var results = $.map(jsonData, function(obj) { // Search if(new RegExp(params.term, "i").test(obj[jsonMap.text])) { return { id:obj[jsonMap.id], text:obj[jsonMap.text] }; } }); callback({ results:results.slice((params.page - 1) * pageSize, params.page * pageSize), pagination:{ more:results.length >= params.page * pageSize } }); }; return CustomDataAdapter; }); var jsonAdapter=$.fn.select2.amd.require('select2/data/customAdapter'); 

扩展此答案以展示如何保留select2附带的搜索function。 谢谢平装作家 !

还引用了如何使用客户端数据源实现无限滚动的示例 ,使用select2版本3.4.5。

此示例使用select标记中的oringal选项来构建列表而不是item数组,这是我的情况所要求的。

 function contains(str1, str2) { return new RegExp(str2, "i").test(str1); } CustomData.prototype.query = function (params, callback) { if (!("page" in params)) { params.page = 1; } var pageSize = 50; var results = this.$element.children().map(function(i, elem) { if (contains(elem.innerText, params.term)) { return { id:[elem.innerText, i].join(""), text:elem.innerText }; } }); callback({ results:results.slice((params.page - 1) * pageSize, params.page * pageSize), pagination:{ more:results.length >= params.page * pageSize } }); }; 

这是一个jsfiddle

这不是一个直接的答案:经过一段时间的努力,我最终转向选择。 Select4对非Ajax搜索的支持,因为版本4,非常复杂,接近荒谬,并没有很好地记录。 Selectize明确支持非Ajax搜索:您只需实现一个返回列表的函数。