改造 Combo Select支持服务器端模糊搜索

项目中使用了 combo select,为缺省的select增加模糊搜索的功能,一直运行得很好。

1    碰到的问题

但最近碰到一个大数据量的select:初始化加载的数据项有2000多个。我们采用的是ajax读取所有的option json,并由js在浏览器中遍历并最终生成完整的html。当数据量变大的时候,ajax读取数据和浏览器处理数据都会有比较明显的损耗,页面初始化时需要较长时间,降低了用户友好度。

2    备选解决方案

大家简单分析了一下这个问题,想到了三种可能的解决方案。

2.1 修改数据结构

目前的同级数据有2000多条,数据从逻辑上可以拆分为两级结构。这样,将数据拆分为两级结构后,使用两个联动Select,能大大减少每个select加载的option数量。

2.2 使用redis缓存数据

因为采用分布式部署,这些数据实际上经过了多次服务器之间的传输。数据量大,每一级传输耗时增加,导致最终的耗时难于接受。

可以在api server端利用nosql对数据进行缓存,能在一定程度上降低耗时。

2.3 修改combo select插件

从前端入手,select只显示少量数据,当用户输入关键字进行搜索时,实时从服务器加载。这种方式增加了调用次数,但可以大大降低数据量,缩短页面加载的耗时。

三种方案,都能在一定程度上解决问题。我们决定先从combo select插件尝试,如果达不到效果,再考虑redis缓存或修改数据结构的方案。

3    Combo Select代码分析

网址 https://github.com/PebbleRoad/combo-select ,感谢提供如此优秀的一个插件。

3.1 基本用法

首先在页面中构建一个select,并初始化option数据,然后调用脚本


$("#selectId").comboSelect();

其他更复杂的功能,请自行前往官网学习。

3.2 html结构

Combo Select在执行时,在原 select 外层套了一个 <div class=”combo-select”>,然后在select后面添加了三个element。

div.combo-arrow,是下拉箭头

ul.combo-dropdown是用来显示的下拉列表

input.combo-input 是用来输入模糊搜索内容的输入框

并通过修改原 select 的属性,隐藏掉。

3.3 js数据模型

combo select初始化时,经过一系列代码,最终构造几个属性:

$container : 生成一个新的div,将原来的select和新生成的ul等都放在其中。

$el : 初始的select element

$options : 所有的option 数据

$dropdown : 生成的 ul.combo-dropdown 对象

$items : 所有的options转成 li 格式后的数据。

下图是数据模型和html元素之间的对应关系。

3.4 插件初始化

在js插件的代码function Plugin ( element, options )会完成插件的初始化,根据select当前的数据,完成html元素的调整,以及js数据模型的初始化。初始化流程如下

3.5 模糊查询的逻辑

当用户在input中输入文字的时候,会触发 keydown和keyup事件,在keyup事件中,对 $items中的数据依次进行匹配,设置 visible属性,实现部分数据的展示。

在这个过程中,原始的select($el)及其所有的options($options)没有变化,下拉列表的变化,主要是将ul.li($items)设置为可见或不可见。

4    修改为Server端实时查询方案

整个修改方案,分别从Server API、js组件、前端调用三方面解决。

4.1 Server API 修改

Server端需要提供根据名称进行模糊搜索的接口。不赘述,需要注意的是返回数据要设置最大条数。避免根据查询条件返回了大量的数据,就失去了解决的优势。

限制最大条数后,需要跟产品介绍清楚这个实现逻辑,如果用户输入的关键字区分度不大时,可能无法查到真正需要的数据;此时需要用户输入更具有区分度的关键字。

4.2 ComboSelect组件修改

4.2.1      修改方案

修改keyup事件时的逻辑:原来是分别设置ul.li是否可见,修改为重新加载select的所有options,并根据options重建$items,并设置为所有ul.li都是可见的。

4.2.2      为组件新增几个参数


entity: ‘entity‘,

itemName: ‘itemName‘,

curItemField: ‘curItemCode‘,

curItemValue: ‘‘,

curItemName: ‘‘,

url: ‘‘,

limit: 7

  • entity: 当前处理的数据类型,这是为了适应不同api返回的json定义的差异。更好的办法是要求所有数据类型使用相同的属性名;变通的方案就是增加这个entity,在js上做差异化处理。这样就减少了改造的通用性。
  • itemName: 调用api时需要的用户输入值的参数名
  • curItemField:在html中,item的input名称
  • curItemValue: 当前已选中数据的value
  • curItemName: 当前已选中数据的title
  • limit: 服务器api模糊搜索返回值的分页大小

4.2.3      修改 _filter() 方法实现服务器端模糊查询

修改了原组件的这个方法,判断是否设置了服务器端刷新的url。如果没设置,沿用原来的逻辑;如果设置了,根据用户输入进行模糊查询,并重新生成浏览器中被隐藏的select的所有options,并更新到$dropdown中。


if(self.settings.url != ‘‘){

// 准备调用api需要的json数据

var self = this;

var ajaxData = {

"paging": true,

"offset": 0,

"limit": self.settings.limit

};

if(self.settings.itemName != ‘‘ && needle != ‘‘){

ajaxData[self.settings.itemName] = needle;

}

if(self.settings.curItemField != ‘‘ && self.settings.curItemValue != ‘‘){

ajaxData[self.settings.curItemField] = self.settings.curItemValue;

}

// 从服务器查询数据

$.ajax({

url : self.settings.url,

type : ‘post‘,

data: ajaxData,

success : function(data) {

var obj = $.parseJSON(data);

// 先删掉select原来的数据,并遍历查询结果生成option添加到select中

var dropdownHtml = ‘‘, k = 0, p = ‘‘;

self.$el.empty();

self.$el.append("<option value=‘‘>请选择</option>");

var confirmedValue;

self.$dropdown.html("<li class=‘option-item‘ data-index=‘0‘ data-value=‘‘>请选择</li>");

for (var i = 0; i < obj.length; i++) {

var itemCode;

var itemName;

var itemExtraCode;

if(self.settings.entity == ‘entity‘){

itemCode = obj[i].entityCode;

itemName = obj[i].entityName;

itemExtraCode = obj[i].entityShortName;

}else{

itemCode = obj[i].itemCode;

itemName = obj[i].itemName;

itemExtraCode = itemCode;

}

// 生成select option

var oneOption = $("<option></option>");

$(oneOption).val(itemCode);

$(oneOption).html(itemName);

if(itemCode == self.settings.curItemValue || itemExtraCode == self.settings.curItemValue || itemName == self.settings.curItemName){

$(oneOption).attr("selected", "selected");

self.settings.curItemValue = itemCode;

confirmedValue = itemCode;

}

self.$el.append(oneOption);

if(confirmedValue != undefined && confirmedValue != ‘‘){

self.$el.val(confirmedValue);

}

// 生成$dropdown 中的li

var oneItem = $("<li></li>");

$(oneItem).attr("class",this.disabled? self.settings.disabledClass : "option-item");

$(oneItem).attr("data-index", (i+1));

$(oneItem).attr("data-value", itemCode);

$(oneItem).html(itemName);

self.$dropdown.append(oneItem);

}

// 为$items 重新赋值

self.$items = self.$dropdown.children();

// 触发后续的open方法

self.$container.trigger(‘comboselect:open‘)

}

});

}

4.2.4      修改 init() 实现首次加载

代码类似_filter()。应该要独立出一个方法来在两个方法中调用,没做。


init: function () {

var self = this;

if(self.settings.url != ‘‘){

//动态刷新代码

... ...

}else{

// 组件的原始逻辑

self._construct();

self._events();

}

},

4.3 前端调用

4.3.1      html代码中添加参数

使用 comboselect- 前缀,如


<select class="list-filedV" id="entityCode" name="entityCode"

comboselect-entity="entity" onchange="getBranch(‘‘)">

</select>

<input type=‘hidden‘ name=‘entityName‘ id=‘entityName‘>

4.3.2      js生成没有缺省值的combobox

在js代码中完成初始化,代码


//获取数据

function getEntityData(){

$("#entityCode").comboSelect({

"itemName": "entityName",

"url": contextPath+"/new/dictionary/searchEntityData.ajax",

"limit": 7

});

}

4.3.3      js生成有缺省值的combobox

在编辑界面比较常见


//获取数据_修改

function getEntityDataUp(curEntityCode, curEntityName){

$("#entityCode").comboSelect({

"itemName": "entityName",

"curItemField": "includeEntityCode",

"curItemValue": curEntityCode,

"curItemName": curEntityName,

"url": contextPath+"/new/dictionary/searchEntityData.ajax",

"limit": 7

});

}

5    降低调用服务器频度

注意看_keyup 的代码,每次按键(不包括该函数忽略的特殊字符),每次都会刷新数据。如果是在浏览器内部进行数据过滤,问题还不明显。但每次模糊查询都通过服务器查询,就会带来大量的api访问。

5.1 修改方案

在_keyup()中,调用_delayFilter(),由它触发前面修改后的 _filter()方法。

5.2 代码 _delayFilter()


this.filterTimer = 0;

_delayFilter: function(search){

if(this.filterTimer > 0){

clearTimeout(this.filterTimer);

this.filterTimer = 0;

}

var self = this;

this.filterTimer = setTimeout(function(){

self._filter(search);

}, 500);

},

原文地址:https://www.cnblogs.com/codestory/p/8178409.html

时间: 2024-10-19 17:36:44

改造 Combo Select支持服务器端模糊搜索的相关文章

改造jQuery-Tagit 插件支持中文全角的逗号和空格

jQuery 的 tagit 插件效果还是不错的,今天用到该插件但发现不能自定义标签分隔符,只能是英文半角逗号或空格,于是想改造下 效果: 先研究了一番插件的代码,发现并不能通过插件自身的扩展方法来实现, 标签输入框是插件自己生成的,所以本来想在外部绑定 keydown 事件但由于事件绑定先后顺序的问题不能实现,只能修改代码了: 改动不多,主要是增加了三个事件绑定在插件原来的 keydown 事件之前绑定一个自定义的 keydown 以及 blur 事件处理标签内容的过滤,以及 keyup 后模

jquery Combo Select 下拉框可选可输入插件

Combo Select 是一款友好的 jQuery 下拉框插件,在 PC 浏览器上它能模拟一个简单漂亮的下拉框,在 iPad 等移动设备上又能回退到原生样式.Combo Select 能够对选项进行检索过滤,同时支持键盘控制. 支持浏览器: Safari, Chrome, Firefox, Opera iOS, Android, IE Mobile Internet Explorer IE 8 and above 开源地址:http://www.oschina.net/p/combo-sele

全面掌握Mysql及select支持的运算操作

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/45725317 花了2天时间整理了一下Mysql中的常用命令及select支持的运算操作,希望这篇博客对大家有所帮助. 内容提纲 1.登录mysql 2.查看mysql信息 3.查看所有数据库 4.打开指定数据库 5.李处指定数据库中的所有表 6.查看指定表的结构 7.查看建表语句 8.建库建表 9.修改指定表结构 10.查看数据库的编码方式 11.DML语句(CRUD)操作 12.注释方

select 支持宽高(高度有兼容问题);

<select size=1(默认) size=2 没有下拉效果> <option selected>12</option> <option selected>635</option> <option selected>245</option> <option selected>666</option> option不支持宽高,display.line-height \ font-size <

Sqoop-1.4.6 Merge源码分析与改造使其支持多个merge-key

Sqoop中提供了一个用于合并数据集的工具sqoop-merge.官方文档中的描述可以参考我的另一篇博客Sqoop-1.4.5用户手册. Merge的基本原理是,需要指定新数据集和老数据集的路径,根据某个merge-key,在reduce过程中,优先取出新数据集中的数据,共同合并成新的全量数据.具体的逻辑分析可以稍后通过看Sqoop-1.4.6的源码来进一步了解. 但是,在原生的Sqoop中,目前只支持merge-key为一个字段的情况,本文通过分析源代码并对源代码进行更改,可以在使用Sqoop

Linux的I/O多路复用机制之--select&poll

1. Linux下的五种I/O模型 1)阻塞I/O(blocking I/O)2)非阻塞I/O (nonblocking I/O)3) I/O复用(select 和poll) (I/O multiplexing)4)信号驱动I/O (signal driven I/O (SIGIO))5)异步I/O (asynchronous I/O (the POSIX aio_functions)) (前四种都是同步,只有最后一种才是异步IO.) 五种I/O模型的比较: 2.多路复用--select 系统提

web前端优化之combo handler 的引入(3)

背景 Combo Handler 是 Yahoo! 开发的一个 Apache 模块,它实现了开发人员简单方便地通过URL来合并JavaScript和CSS文件,从而大大减少文件请求数. 目的 它满足 Yahoo! 前端优化第一条原则:Minimize HTTP Requests,来减少三路握手和HTTP请求的发送次数. 国内实例 淘宝网首页meta里多个js合并的声明: js之间用英文逗号或&符号分隔.此src的Response是多个js文件的内容拼装. 国内的 Combo Script 支持

UNIX网络编程:I/O复用技术(select、poll、epoll)

Unix下可用的I/O模型一共有五种:阻塞I/O .非阻塞I/O .I/O复用 .信号驱动I/O .异步I/O.此处我们主要介绍第三种I/O符复用. I/O复用的功能:如果一个或多个I/O条件满足(输入已准备好读,或者描述字可以承接更多输出)时,我们就被通知到.这就是有select.poll.epoll实现. I/O复用应用场合: 1.当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用.在这前一段中已做描述. 2.一个客户同时处理多个套接口是可能的,但很少出现. 3.如果

自己写的一个简单的迅雷下载支持断点续传

当我学习了网络线程,就自己仿照迅雷下载写了一个下载器,支持断点续传 我用的是SWT插件做的界面 界面 package com.yc.xunlei; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.Arra