一、数据列表内置功能
-
原生autocomplete功能
会记忆当前输入框经过表单提交过的值,并在下一次连续点击的时候出现autocomplete数据列表。
使用示意:
<form> <p> <span class="ui-input ui-search-input"> <input type="search" id="simple" name="search" results="5" required> <label class="ui-icon-search" for="submit">搜索</label> </span> <input type="submit" id="submit" class="clip"> <a href="javascript:" id="clearStore">清除输入框数据</a> </p> </form>
// 这个是让大家知道表单提交就会自动存储 new Validate($('form').eq(0), function() { $.lightTip.success('搜索内容已经在本地存储'); });
var elSimple = $('#simple'); // 其实就这一行代码 var simpleList = new Datalist(elSimple); $('#clearStore').click(function() { simpleList.removeStore(); $.lightTip.success(simpleList.value() + '已经从本地数据中清除'); });
本组件原本作用就是实现这里的「输入历史记录」功能的,后面的动态匹配什么的,都是附带的。
采用和浏览器自身一样的机制实现,包括:
<form>
元素submit
事件执行的时候,才会记录该数据;- 数据查询key通过
name
属性值进行匹配; autocomplete="off"
可以关闭自动提示和记忆功能。- 操作交互也和浏览器内置交互一致,例如,输入框2此点击,显示对应列表,上下键选择,回车赋值等。
换句话说,就是把浏览器内置的autocomplete功能美化了下,所谓UI组件,本来就应该关注UI.
当选择列表内容之后,默认会触发
<input>
输入框的change
事件,基本上做到与业务事件的分离。 -
基于ajax动态返回数据的autocomplate功能
<form action="datalist.html"> <input class="ui-input" type="search" id="ajaxSearch" name="key" size="30" placeholder="输入字母"> <label class="ui-button ui-button-primary" for="sSubmit">搜索</label> <input type="submit" id="sSubmit" class="clip"> </form>
new Datalist($('#ajaxSearch'), { data: { url: '/search', data: { userid: 1 }, success: function() { console.log('success callback success!'); } } });
这里的datalist数据由后端提供,前端发送搜索内容给后端,通过返回数据展现。
data
参数设置为Ajax请求对象(和jQuery$.ajax
方法参数一致),其中url
属性是必须的。一旦Ajax datalist初始化,会给输入框添加
autocomplete="off"
关闭浏览器内置的自动完成。默认是'json'类型数据。
其中,请求的
data
参数和success
参数和组件内部的参数设置合并。其中:data
参数,都懂的,就是我们要把搜索文字动态发送过去,因此,需要内置。查询关键字就是<input>
元素的name
属性值,如果缺省,使用字符k
代替;- 组件内的
success
作用是呈现列表,如果你有其他成功回调处理,直接设置,不冲突,两者走的合并策略。
然而,我们实际使用的时候不会像上面这么简单,因此不同项目不同开发返回的数据格式和后台接口都是不一样的。本Datalist组件支持的返回数据结构结构如下:
{ data: [] }
也就是前后端接口是
data
,这个其实比较好满足,关键是data
后面属性值不一定是Datalist需要的数组格式,可能这样:{ data: { pageInfo: {}, data: [] } }
也就是数据列表是
data.data
,此时,我们可以使用filter
参数处理,filter
参数是个专门对数据进行过滤和处理的方法,例如,我们可以这样:new Datalist($('#ajaxSearch'), { data: { url: '/cgi/search.php', filter: function(data) { return data.data; } } });
如果更进一步,
data.data
数组中的对象属性名不是value
(必须),也不是label
(可缺省),而是其它,例如:{ data: { pageInfo: {}, data: [{ content: 'aaaaa' }, { content: 'bbbbb' }] } }
此时,同样在
filter
方法中进行处理,返回Datalist需要的数组格式就可以了:new Datalist($('#ajaxSearch'), { data: { url: '/cgi/search.html', filter: function(data) { return $.map(data.data, function (obj) { return { value: obj.content } }); } } });
-
静态数据的动态匹配
例如下面的邮箱自动补全功能:
邮箱:
邮箱:<input type="email" id="emailMatch" class="ui-input" size="30">
new Datalist($('#emailMatch'), { data: ['qq.com', 'gmail.com', '126.com', '163.com'], filter: function(data, value) { var value = value.split('@')[0]; return $.map(data, function(domain) { return { value: value + '@' + domain }; }); } });
-
带滚动条的测试
选择工作项:连续点击2次输入框var manyList = new Datalist($('#manyList'), { data: [{ label: 'top1', value: '企点服务迭代三(4月6日~5月5日)' }, ... , { label: 'top11', value: '视觉体验迭代' }], max: 'auto' }); // 设置为'auto'则双击空输入框时候也会出现列表 manyList.params.data = 'auto';
二、语法和API参数
-
语法
new Datalist(trigger, options);
或者链式调用:
trigger.datalist(options);
-
API参数
trigger
默认就是指的我们的输入框,options
为可选参数,具体见下表:参数名称 支持类型 默认值 释义 data String|Array|
Function|Object'auto'
列表的数据,默认 auto
表示从本地获取;
还可以是静态数组,数组内为类似下面结构的对象:{
也可以是Function动态获取数据内容;
label: '', // 可选,右侧小文字
value: '' // 必须
}
也可以是Ajax请求数据对象。max String|Number 8
最多显示的列表项条数,默认8条。使用关键字 'auto'
表示数据没有限制。可以使用HTML原生的类目个数属性results
重置显示的条目数,例如results="5"
最多显示5条列表数据。width String|Number 'auto'
列表的宽度,默认 'auto'
表示和trigger
触发元素的outerWidth宽度一致。container Object $(document.body)
jQuery包装器对象,指装载列表的容器,默认直插页面。 filter Function function(data, value) {
/* 首字符匹配过滤 */
}对现有的数据进行重新过滤或者重新组装,只要返回需要的数组就好了,数组格式和细节和 data
参数一致。其中,this
上下文指当前实例元素,支持2个参数,data
为需要处理的数据(也是数组格式),value
是输入框xss过滤后的值。trigger String|Array ['change']
当选值时候触发的文本框的事件类型。 onShow Function $.noop
列表显示时候触发的回调。 this
上下文指当前实例元素,支持2个参数,分别是触发元素trigger
和列表面板元素target
.onHide Function $.noop
列表隐藏时候触发的回调。 this
上下文指当前实例元素,支持2个参数,分别是触发元素trigger
和列表面板元素target
. -
关于实例对象
假设我们有一个名为myDatalist的实例对象,代码为:
var myDatalist = new Datalist(el);
则
myDatalist
对象暴露了如下属性和方法:{ el: { // 输入框元素 trigger: $(), // append列表的容器 container: $(), // 列表面板元素 target: $() }, callback: { trigger: [], // 这个根据params.data生成的获得实时列表数据的方法,真正的数据源 data: $.noop, filter: $.noop, show: $.noop, hide: $.noop }, params: { width: params.width, max: params.max, // 初始化完成,就作为标志量使用(如设为'auto'就能focus显示列表) data: params.data, index: -1 }, bool: { modern: true|false }, display: true|false, // 当前列表所使用的数据 data: [], // 存储本地输入框的值 store: $.noop, // 清除本地记录,支持1个可选的value参数,有3种逻辑: 1. 字符串内容,表示移除本地该值数据(如果有) 2. true, 表示清空本地对应该存储 3. undefined, 表示使用trigger输入框的value值作为移除对象 removeStore: $.noop, // 根据当前value值刷新列表,支持一个可选的
data
参数,表示使用指定数据进行列表呈现。 refresh: $.noop, create: $.noop, // 支持一个可选参数,类似jQuery $().val(value)方法,有参数表示赋值,没有表示获取值。 这里返回的是输入框xss过滤后的数值。 value: $.noop, events: $.noop, // 列表定位 position: $.noop, // 显示列表 show: $.noop, // 隐藏列表 hide: $.noop }如果使用的是jQuery链式调用语法,则实例对象可以这么获取。
el.datalist(); var myDatalist = el.data('datalist');
也就是实例对象通过
data
方法存储在了jQuery元素上。
三、基于数据列表拓展的案例
-
带搜索的下拉列表
使用CSS重置了一些样式,例如,绝对定位就不要了,阴影效果也不要了:
.datalist_container .ui-datalist { display: block!important; position: static!important; } .datalist_container .ui-datalist-datalist { margin-top: 10px; border: 1px solid #d0d0d5; box-shadow: none; }
这里的按钮HTML直接取自Select组件UI,因为我懒:
<div class="ui-select" style="width:300px;"> <a href="javascript:" id="select" class="ui-select-button"><span class="ui-select-text">企点服务迭代三(4月6日~5月5日)</span><i class="ui-select-icon"></i></a> </div>
然后是JS代码,使用了组件体系中的Drop.js,而这里的Datalist则静态处理:
// 这里展开浮层的HTML结构,有个搜索框还有一个容器 var htmlDrop = '<div class="ui-droplist-x">\ <div class="p10">\ <div class="ui-input ui-search-input ui-search-right"> <input type="search"> <label class="ui-icon-search">搜索</label> </div>\ <div id="cont" class="datalist_container"></div>\ </div>\ </div>'; var trigger = $('#select'), target = $(htmlDrop); // 面板的宽度和按钮一样宽 target.width(trigger.outerWidth()); // 使用Drop.js new Drop(trigger, target, { eventType: 'click', onShow: function(trigger, target) { var drop = this; var input = target.find('input'), span = trigger.find('span'); if (!this.datalist) { // 只构造一次 var datalist = new Datalist(input, { data: data, width: 280, container: target.find('#cont'), max: 'auto' }); datalist.params.data = 'auto'; datalist.refresh(); // 事件 datalist.el.target.delegate('li', 'click', function() { span.html($(this).attr('value')); drop.hide(); }); input.on('input', function() { if (this.value == '') { // 空值显示完整列表 datalist.refresh(); } }).on('keydown', function(event) { if (event.keyCode == 13) { // 回车选中 var selected = datalist.el.target.find('.selected'); if (selected.length) { span.html(selected.attr('value')); drop.hide(); } } }); this.datalist = datalist; } else { input.val(''); this.datalist.refresh(); } // 高亮选中的元素 this.datalist.el.target.find('li').each(function() { if ($(this).attr('value') == span.html()) { $(this).addClass('selected'); } }); } });
上面代码更多示意目的,未严格验证(如IE8不支持input事件),大家如果有需求,可以整到项目的一些拓展组件库里面去。
上面的搜索功能采用的是默认的从前往后字符严格匹配,如果想支持首字母查询,或是模糊查询,使用
filter
参数,把filter
设置为自己想要的查询方法即可!
四、作为插件使用
引入CSS:
<link rel="stylesheet" href="//qidian.gtimg.com/lulu/theme/peak/css/common/ui/Datalist.css">
引入JS(jquery文件略):
<script src="//qidian.gtimg.com/c/=/lulu/theme/peak/js/common/ui/Follow.js,/lulu/theme/peak/js/common/ui/Datalist.js"></script>