JS列表的下拉菜单组件(仿美化控件select)

2014-01-23 23:51 by 龙恩0707, 1101 阅读, 6 评论, 收藏编辑

今天是农历23 也是小年,在这祝福大家新年快乐!今天给大家分享的是:JS列表的下拉菜单组件,因为目前项目正好要用到这个,所以提前研究了下,看到KISSY也有这么一个组件,所以自己也封装了一个,KISSY demo链接

KISSY组件名字叫 "一个解决大数据列表渲染效率的下拉菜单组件。", 他对这个组件做了一次小优化。(假如服务器返回10000条数据或者更多的话,那么我们前端一次性操作10000条数据的话很会影响性能,他们做的优化是:将数组拆分,根据浏览器本身的脚本执行能力进行分批渲染。),但是目前kissy demo上有加载2000条数据的demo,在火狐下还是会有卡住的现象,如果稍不好的话 有可能会导致浏览器重启的可能。而我今天做的demo和他们的功能类似,但是唯一不同点就是:假如返回10000条数据的话 我没有对数组分批渲染,而是循环10000次 把数据保存到一个变量里 然后一次性动态加载进来,或许这么做和他们那种操作效率可能会低那么点(具体的我没有测试过)。所以我今天的标题没有和他们那样一起叫。所以今天的标题上:"JS列表的下拉菜单组件". 首先要说明的是:一般的需求肯定是满足的,一个下拉框也不可能有那么多数据(一般情况下!)。

下面是我做的demo(JS列表的下拉菜单组件)。JSFiddle地址如下:

想要看demo,请轻轻的点击我!我怕疼的!温柔点!

基本原理:

满足的基本功能是:一个基本下拉框,但是他与下拉框不同的是:他既可以输入精确匹配到某一项,也可以点击下拉,也支持键盘上下移操作。但同时当我在输入框输入时候没有匹配到某一项时候,点击文档document 那么下拉框隐藏掉,input值为空。同时且支持静态数据渲染 又支持post请求渲染数据。

基本的配置项如下:

  parentCls
'.parentCls',   输入框父元素class 默认
inputElemCls  '.inputElem',     目标元素的class
inputWidth  100,               目标元素的宽度 单位(PX)
 selectCls   '.caret',            下来小箭头class
hoverBg 'hoverBg',          鼠标移上去的背景
isSelectHide true,                  点击下拉框某一项 是否隐藏 默认true
timeId 100,                  默认多少毫秒消失下拉框
dataSource [],                    数据源返回的格式如下:静态数据 否则的话   (如果数组为空的话) 在内部发post请求
renderHTMLCallback  null               keyup时 渲染数据后的回调函数
callback  null                点击某一项 提供回调

如上面配置: 其中dataSource如果初始化为空数组的话,那么直接在内部发post请求渲染数据,否则的话 也可以渲染静态数据:如下

dataSource: [
            {text: "列表项1", value: 1},
            {text: "列表项2", value: 2},
            {text: "列表项3", value: 3},
            {text: "列表项4", value: 4},
            {text: "列表项5", value: 5},
            {text: "列表项6", value: 6},
            {text: "列表项7", value: 7},
            {text: "列表项8", value: 8},
            {text: "列表项9", value: 9},
            {text: "列表项10", value: 10},
            {text: "列表项11", value: 11}
        ]

如果dataSource 的长度大于0 的话 那么他会按照静态数据渲染,不会发post请求 否则的话 (如果数组为空,支持发post请求) 去渲染数据。

对外提供的方法有:

setValue()

在外部实例话后 可以调用此方法 设置初始化值。比如demo页面设置的格式如下:
        // 设置初始化选择项。
        selectedItem: {
            value: "4",
            text: "列表项4"
        }

getValue();   获取输入框的值。

代码简单的分析下:

首先初始化init方法:代码如下:

init: function(options) {
this.config = $.extend(this.config, options || {});
var self = this,
_config = self.config,
_cache = self.cache;
$('.drop-trigger').css({"left":_config.inputWidth - 20 + 'px'});
/*
* 鼠标点击输入框时 渲染数据
*/
$(_config.inputElemCls).each(function(index,item){ // 对input定义宽度 其父节点div也是根据input宽度定义的。
$(item).css({'width':_config.inputWidth});
var tagParent = $(item).closest(_config.parentCls);
$(tagParent).css({'width':_config.inputWidth}); $(item).bind('keyup',function(e){
e.preventDefault();
var targetVal = $.trim($(this).val()),
keyCode = e.keyCode,
elemHeight = $(this).outerHeight(); var targetParent = $(this).closest(_config.parentCls);
$(targetParent).css({'position':'relative'}); // 删除标识
self._removeState(targetParent); var curIndex = self._keyCode(keyCode);
if(curIndex > -1) {
// 除了列举那些键码不发请求
self._keyUpAndDown(targetVal,e,targetParent);
}else {
// 渲染数据
self._renderHTML(targetVal,targetParent,elemHeight); // 如果值为空的话 那么下拉列表隐藏掉
if(targetVal == '') {
self._hide(targetParent);
_cache.currentIndex = -1;
_cache.oldIndex = -1;
}else {
self._show(targetParent);
}
}
}); var targetParent = $(item).closest(_config.parentCls);
$(_config.selectCls,targetParent).unbind('click');
$(_config.selectCls,targetParent).bind('click',function(){ var targetVal = $.trim($(item,targetParent).val()),
elemHeight = $(item,targetParent).outerHeight();
// 渲染数据
self._renderHTML(targetVal,targetParent,elemHeight);
});
}); /*
* 点击document 不包括input输入框时候 隐藏下拉框
*/
$(document).unbind('click');
$(document).bind('click',function(e){
e.stopPropagation();
var target = e.target,
targetParent = $(target).closest(_config.parentCls);
var reg = _config.inputElemCls.replace(/^\./,''),
selectCls = _config.selectCls.replace(/^\./,'');
if($(target,targetParent).hasClass(reg) || $(target,targetParent).hasClass(selectCls)) {
return;
}else {
self._hide(targetParent);
}
$(_config.inputElemCls).each(function(index,item){
if(!$(item).hasClass('state')) {
$(item).val('');
}
}); });
},

其中上面的 // 对input定义宽度 其父节点div也是根据input宽度定义的。 $(item).css({'width':_config.inputWidth}); var tagParent = (item).closest(config.parentCls);(tagParent).css({'width':_config.inputWidth});

这几句代码的意思是:

1 初始化时候 动态的设置input框的宽度 其中父元素的宽度也是根据input宽度来设置的,且下面的代码 下拉框的宽度也是根据input宽度渲染的。

2. 分别对input绑定keyup事件及下拉框小箭头绑定点击click事件做相应的操作。首先keyup操作时,调用这个方法 self._removeState(targetParent);删除相应的class (state),因为下面有当我用键盘下拉移到某一项时或者鼠标点击下拉框某一项时候 会增加class(state),这样做的目的是当我点击document时候会判断input输入框是否有这个class(state),如果没有的话 清空input输入框的值。否则的话,反之!接着判断键码 var curIndex = self._keyCode(keyCode); 这个方法.目的是为了当用上面那些键盘在输入框操作时候 不发post请求(也就是说除了那些常见的键码外发post请求)。如果键码等于40的话 那么执行下移操作,如果等于38的话 那么是上移操作。否则的话 调用_renderHTML方法 渲染数据。(同样当点击下拉小箭头时候也调用此方法渲染数据。),下面的代码是点击文档document时候 首先判断是否是输入框或者是小箭头的话,下拉框不做任何处理,否则的话 隐藏掉。点击document时候 做了另外一件事,就是说 如果此input没有state类名时候清空输入框数据。

_renderHTML方法代码如下:

_renderHTML: function(targetVal,targetParent,elemHeight) {
var self = this,
_config = self.config,
_cache = self.cache; // 如果已经渲染了 先清空数据
if($('ul',targetParent).length > 0) {
self._show(targetParent);
$('ul',targetParent).html('');
}
if(_cache.onlyCreate) {
$(targetParent).append($('<ul></ul>'));
_cache.onlyCreate = false;
}
var html = '';
/*
* 如果设置了静态数据的话 那么直接使用静态数据 否则的话 发post请求
* 由于代码没有用 模板 所以直接for循环
*/
if(_config.dataSource.length > 0) { for(var i = 0, ilen = _config.dataSource.length; i < ilen; i+=1) {
if(_config.dataSource[i].text.indexOf(targetVal) >= 0) {
html+= '<li class="dropmenu-item p-index'+i+'" data-value="'+_config.dataSource[i].value+'" data-title="'+_config.dataSource[i].text+'">'+_config.dataSource[i].text+'</li>';
}else {
$('ul',targetParent).css({'border':'none'});
}
} $('ul',targetParent).append(html);
}else {
// 发post请求
/**$.ajax({
type: 'post'
});**/ // 假如返回的数据 如上所示的格式
var result = [
{text: "列表项1", value: 1},
{text: "列表项2", value: 2},
{text: "列表项3", value: 3},
{text: "列表项4", value: 4},
{text: "列表项5", value: 5},
{text: "列表项6", value: 6},
{text: "列表项7", value: 7},
{text: "列表项8", value: 8},
{text: "列表项9", value: 9},
{text: "列表项10", value: 10},
{text: "列表项11", value: 11}
];
for(var i = 0, ilen = result.length; i < ilen; i+=1) {
if(result[i].text.indexOf(targetVal) >=0) {
html+= '<li class="dropmenu-item p-index'+i+'" data-value="'+result[i].value+'" data-title="'+result[i].text+'">'+result[i].text+'</li>';
}else {
$('ul',targetParent).css({'border':'none'});
}
}
$('ul',targetParent).append(html);
}
$('ul',targetParent).css({
"width":_config.inputWidth,
'overflow':'hidden','border':'1px solid #ccc','border-top':'none'});
$('ul,li',targetParent).css({'cursor':'pointer'}); var len = $('li',targetParent).length;
if(len >= 10) {
$('ul',targetParent).css({'height':'220px','overflow':'scroll'});
}else {
$('ul',targetParent).css({'height':'auto','overflow':'hidden'});
}
// hover事件
self._hover(targetParent);
// 渲染后回调函数
_config.renderHTMLCallback && $.isFunction(_config.renderHTMLCallback) && _config.renderHTMLCallback(); // 点击下来框某一项
self._clickItem(targetParent);
},

代码做了如下事情:

1. 如果ul已经创建了(只创建一次) 则显示且清空之前的数据。

2.如果设置了静态数据的话(dataSource.length > 0) 那么直接使用静态数据 否则的话 发post请求.

3. 如果下拉框数据渲染时候 长度大于10的话 添加滚动条,否则的话 不添加。

接着就调用如下方法:

// hover事件
self._hover(targetParent); // 渲染后回调函数
_config.renderHTMLCallback && $.isFunction(_config.renderHTMLCallback) && _config.renderHTMLCallback(); // 点击下来框某一项
self._clickItem(targetParent);

下面是所有的代码如下:

HTML依赖的结构如下:

<div class="parentCls">
<div class="drop-trigger"><i class="caret"></i></div>
<input type="text" class="inputElem" autocomplete="off"/>
</div>

其中父级元素class默认为 parentCls,可以根据自己自定义 如有需要 可以根据具体的值进行传,input的类名class 默认为inputElem 也可以自定义。

CSS代码我就不贴了。可以根据自己的需要自己写。如有需要或者可以看看JSfiddle源码 看看css代码。

下面是所有JS代码如下:

/**
* 一个解决大数据列表渲染效率的下拉菜单组件。
* @author tugenhua
* @time 2014-01-21
*/

function DropList(options) {

this.config = {
parentCls : '.parentCls', // 父元素class
inputElemCls : '.inputElem', // 当前input标签input的class
inputWidth : 100, // 目标元素的宽度
selectCls : '.caret', // 下来小箭头class
hoverBg : 'hoverBg', // 鼠标移上去的背景
isSelectHide : true, // 点击下拉框 是否隐藏
timeId : 100, // 默认多少毫秒消失下拉框
// 数据源返回的格式如下:静态数据 否则的话(如果数组为空的话) 在内部发post请求
dataSource: [
{text: "列表项1", value: 1},
{text: "列表项2", value: 2},
{text: "列表项3", value: 3},
{text: "列表项4", value: 4},
{text: "列表项5", value: 5},
{text: "列表项6", value: 6},
{text: "列表项7", value: 7},
{text: "列表项8", value: 8},
{text: "列表项9", value: 9},
{text: "列表项10", value: 10},
{text: "列表项11", value: 11}
],
renderHTMLCallback : null, // keyup时 渲染数据后的回调函数
callback : null // 点击某一项 提供回调
};

this.cache = {
onlyCreate : true, // 只渲染一次代码
currentIndex : -1,
oldIndex : -1,
timeId : null // setTimeout定时器
};
this.init(options);
}

DropList.prototype = {

constructor: DropList,

init: function(options) {
this.config = $.extend(this.config, options || {});
var self = this,
_config = self.config,
_cache = self.cache;
$('.drop-trigger').css({"left":_config.inputWidth - 20 + 'px'});
/*
* 鼠标点击输入框时 渲染数据
*/
$(_config.inputElemCls).each(function(index,item){

// 对input定义宽度 其父节点div也是根据input宽度定义的。
$(item).css({'width':_config.inputWidth});
var tagParent = $(item).closest(_config.parentCls);
$(tagParent).css({'width':_config.inputWidth});

$(item).bind('keyup',function(e){
e.preventDefault();
var targetVal = $.trim($(this).val()),
keyCode = e.keyCode,
elemHeight = $(this).outerHeight();

var targetParent = $(this).closest(_config.parentCls);
$(targetParent).css({'position':'relative'});

// 删除标识
self._removeState(targetParent);

var curIndex = self._keyCode(keyCode);
if(curIndex > -1) {
// 除了列举那些键码不发请求
self._keyUpAndDown(targetVal,e,targetParent);
}else {
// 渲染数据
self._renderHTML(targetVal,targetParent,elemHeight);

// 如果值为空的话 那么下拉列表隐藏掉
if(targetVal == '') {
self._hide(targetParent);
_cache.currentIndex = -1;
_cache.oldIndex = -1;
}else {
self._show(targetParent);
}
}
});

var targetParent = $(item).closest(_config.parentCls);
$(_config.selectCls,targetParent).unbind('click');
$(_config.selectCls,targetParent).bind('click',function(){

var targetVal = $.trim($(item,targetParent).val()),
elemHeight = $(item,targetParent).outerHeight();
// 渲染数据
self._renderHTML(targetVal,targetParent,elemHeight);
});
});

/*
* 点击document 不包括input输入框时候 隐藏下拉框
*/
$(document).unbind('click');
$(document).bind('click',function(e){
e.stopPropagation();
var target = e.target,
targetParent = $(target).closest(_config.parentCls);
var reg = _config.inputElemCls.replace(/^\./,''),
selectCls = _config.selectCls.replace(/^\./,'');
if($(target,targetParent).hasClass(reg) || $(target,targetParent).hasClass(selectCls)) {
return;
}else {
self._hide(targetParent);
}
$(_config.inputElemCls).each(function(index,item){
if(!$(item).hasClass('state')) {
$(item).val('');
}
});

});
},
// 键码判断
_keyCode: function(code) {
var arrs = ['17','18','38','40','37','39','33','34','35','46','36','13','45','44','145','19','20','9'];
for(var i = 0, ilen = arrs.length; i < ilen; i++) {
if(code == arrs[i]) {
return i;
}
}
return -1;
},
_renderHTML: function(targetVal,targetParent,elemHeight) {
var self = this,
_config = self.config,
_cache = self.cache;

// 如果已经渲染了 先清空数据
if($('ul',targetParent).length > 0) {
self._show(targetParent);
$('ul',targetParent).html('');
}
if(_cache.onlyCreate) {
$(targetParent).append($('<ul></ul>'));
_cache.onlyCreate = false;
}
var html = '';
/*
* 如果设置了静态数据的话 那么直接使用静态数据 否则的话 发post请求
* 由于代码没有用 模板 所以直接for循环
*/
if(_config.dataSource.length > 0) {

for(var i = 0, ilen = _config.dataSource.length; i < ilen; i+=1) {
if(_config.dataSource[i].text.indexOf(targetVal) >= 0) {
html+= '<li class="dropmenu-item p-index'+i+'" data-value="'+_config.dataSource[i].value+'" data-title="'+_config.dataSource[i].text+'">'+_config.dataSource[i].text+'</li>';
}else {
$('ul',targetParent).css({'border':'none'});
}
}

$('ul',targetParent).append(html);
}else {
// 发post请求
/**$.ajax({
type: 'post'
});**/

// 假如返回的数据 如上所示的格式
var result = [
{text: "列表项1", value: 1},
{text: "列表项2", value: 2},
{text: "列表项3", value: 3},
{text: "列表项4", value: 4},
{text: "列表项5", value: 5},
{text: "列表项6", value: 6},
{text: "列表项7", value: 7},
{text: "列表项8", value: 8},
{text: "列表项9", value: 9},
{text: "列表项10", value: 10},
{text: "列表项11", value: 11}
];
for(var i = 0, ilen = result.length; i < ilen; i+=1) {
if(result[i].text.indexOf(targetVal) >=0) {
html+= '<li class="dropmenu-item p-index'+i+'" data-value="'+result[i].value+'" data-title="'+result[i].text+'">'+result[i].text+'</li>';
}else {
$('ul',targetParent).css({'border':'none'});
}
}
$('ul',targetParent).append(html);
}
$('ul',targetParent).css({
"width":_config.inputWidth,
'overflow':'hidden','border':'1px solid #ccc','border-top':'none'});
$('ul,li',targetParent).css({'cursor':'pointer'});

var len = $('li',targetParent).length;
if(len >= 10) {
$('ul',targetParent).css({'height':'220px','overflow':'scroll'});
}else {
$('ul',targetParent).css({'height':'auto','overflow':'hidden'});
}
// hover事件
self._hover(targetParent);
// 渲染后回调函数
_config.renderHTMLCallback && $.isFunction(_config.renderHTMLCallback) && _config.renderHTMLCallback();

// 点击下来框某一项
self._clickItem(targetParent);
},
/*
* 键盘上下移操作
* @method _keyUpAndDown
* @param targetVal,e,targetParent
*/
_keyUpAndDown: function(targetVal,e,targetParent){
var self = this,
_config = self.config,
_cache = self.cache;

// 如果请求成功后 返回了数据(根据元素的长度来判断) 执行以下操作
if($('li',targetParent) && $('li',targetParent).length > 0) {

var plen = $('li',targetParent).length,
keyCode = e.keyCode;
_cache.oldIndex = _cache.currentIndex;
// 上移操作
if(keyCode == 38) {
if(_cache.currentIndex == -1) {
_cache.currentIndex = plen - 1;
}else {
_cache.currentIndex = _cache.currentIndex - 1;
if(_cache.currentIndex < 0) {
_cache.currentIndex = plen - 1;
}
}
if(_cache.currentIndex !== -1) {

!$($('li',targetParent)[_cache.currentIndex]).hasClass(_config.hoverBg) &&
$($('li',targetParent)[_cache.currentIndex]).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
var curAttr = $($('li',targetParent)[_cache.currentIndex]).attr('data-title');
$(_config.inputElemCls,targetParent).val(curAttr);

// 给当前的input元素增加一个标识
self._state(targetParent);

}

}else if(keyCode == 40) { //下移操作
if(_cache.currentIndex == plen - 1) {
_cache.currentIndex = 0;
}else {
_cache.currentIndex++;
if(_cache.currentIndex > plen - 1) {
_cache.currentIndex = 0;
}
}
if(_cache.currentIndex !== -1) {

!$($('li',targetParent)[_cache.currentIndex]).hasClass(_config.hoverBg) &&
$($('li',targetParent)[_cache.currentIndex]).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);

var curAttr = $($('li',targetParent)[_cache.currentIndex]).attr('data-title');
$(_config.inputElemCls,targetParent).val(curAttr);

// 给当前的input元素增加一个标识
self._state(targetParent);
}

}else if(keyCode == 13) { //回车操作
var curVal = $($('li',targetParent)[_cache.currentIndex]).attr('data-title');
$(_config.inputElemCls,targetParent).val(curVal);

// 给当前的input元素增加一个标识
self._state(targetParent);

// 点击下拉框某一项是否隐藏 下拉框 默认为true
if(_config.isSelectHide) {
self._hide(targetParent);
}
_cache.currentIndex = -1;
_cache.oldIndex = -1;

// 点击某一项后回调
_config.callback && $.isFunction(_config.callback) && _config.callback();

// 按enter键 阻止form表单默认提交
return false;

}
}
},
// 给当前的input元素增加一个标识 目的是判断输入值是否合法
_state: function(targetParent){
var self = this,
_config = self.config;
!$(_config.inputElemCls,targetParent).hasClass('state') &&
$(_config.inputElemCls,targetParent).addClass('state');
},
// 删除input标识
_removeState: function(targetParent) {
var self = this,
_config = self.config;
$(_config.inputElemCls,targetParent).hasClass('state') &&
$(_config.inputElemCls,targetParent).removeClass('state');
},
/*
* hover 下拉框
*/
_hover: function(targetParent){
var self = this,
_config = self.config;

$('.dropmenu-item',targetParent).each(function(index,item){
$(item).hover(function(){
!$(item).hasClass(_config.hoverBg) && $(item).addClass(_config.hoverBg);
},function(){
$(item).hasClass(_config.hoverBg) && $(item).removeClass(_config.hoverBg);
});
})
},
/*
* 点击下拉框某一项
* @method _clickItem
*/
_clickItem: function(targetParent) {
var self = this,
_config = self.config;
$('.dropmenu-item',targetParent).each(function(index,item){

$(item).unbind('click');
$(item).bind('click',function(e){
var target = e.target,
title = $(target).attr('data-title');
$(_config.inputElemCls,targetParent).val(title);

// 给当前的input元素增加一个标识 目的是判断输入值是否合法
!$(_config.inputElemCls,targetParent).hasClass('state') &&
$(_config.inputElemCls,targetParent).addClass('state');

// 点击某一项后回调
_config.callback && $.isFunction(_config.callback) && _config.callback();

// 点击下拉框某一项是否隐藏 下拉框 默认为true
if(_config.isSelectHide) {
self._hide(targetParent);
}
});
});
},
/*
* 显示方法
* @mrthod _show {private}
*/
_show: function(targetParent) {
var self = this,
_config = self.config,
_cache = self.cache;
_cache.timeId && clearTimeout(_cache.timeId);
if($('ul',targetParent).hasClass('hidden')) {
$('ul',targetParent).removeClass('hidden');
}
},
/*
* 隐藏方法
* @method _hide {private}
*/
_hide: function(targetParent) {
var self = this,
_config = self.config,
_cache = self.cache;
_cache.timeId = setTimeout(function(){
if($(targetParent).length > 0) {
!$('ul',targetParent).hasClass('hidden') && $('ul',targetParent).addClass('hidden');
}else {
!$('ul').hasClass('hidden') && $('ul').addClass('hidden');
}
},_config.timeId);
},
/*
* 给输入框设置默认值
* @param {Object}
* @method setValue {public}
*/
setValue: function(obj){
/** 对象格式如下
// 设置初始化选择项。
selectedItem: {
value: "4",
text: "列表项4"
}**/
var self = this,
_config = self.config;
$(_config.inputElemCls).val(obj.text);
},
/*
* 获取输入框的值
* @return value
*/
getValue: function() {
var self = this,
_config = self.config;
return $(_config.inputElemCls).val();
}
};
// 初始化
$(function(){
var a = new DropList({
dataSource: []
});
var selectedItem = {
value: "4",
text: "列表项4"
};
a.setValue(selectedItem);
});

插件不足之处:

1. 在火狐或者google下 当下拉框下拉时候 按上移键 光标会先跳到最前面然后移到最后面,也就是说光标会移动,用户体验稍微有点不好,一般情况下,用户也不会用上下移键,一般用鼠标操作,但是这也是一个小bug,目前没有找到具体的原因。我想可以用HTML5中的Range对象和 selection对象应该有办法解决!后续有时间的话 稍微解决这么一个bug。

2. 第二个不足之处,就是当数据量大的时候(比如数据下拉框有2000条数据甚至更多时候),前端性能肯定会有影响。淘宝kissy他是用的是对返回的数组分批渲染,但是还是有影响的,目前没有发现有什么的更好的方法来解决这么一个大数据的情况。

针对下拉框大数据的时候的个人想法:

首先我们明白 在窗口中页面上假如有10000张图片,我们根据 图片离浏览器顶部的距离是否小于或者等于 可视区离浏览器顶部的距离 进行延迟加载渲染图片,可以有效的提高性能,只加载第一屏幕的数据。那么这个下拉框我们是否也可以根据这个原理也对它做这样的处理:比如页面一开始渲染的时候 我只加载10条数据且有滚动条,那么当我下拉滚动条时候再进行分批渲染相应的数据,不管后台返回我的是10000条数据也好或者更多,我们只关注且页面一开始只渲染前面10条数据,后面的数据根据用户操作下拉滚动条时候进行分别渲染出来,虽然目前我们前端是没有办法监听这个事件的。目前也没有办法做到的,但是我今天站在用户角度来考虑这么一个问题的。或许随着时间越长,未来的技术可以解决这么一个问题的。期待中.......

总结:

2014年春节前,这篇博客有可能是最后一篇了,如有不足之处,请大家多多指教!已经买了28号凌晨2点的火车回家,嘿嘿!明年继续研究代码,研究前端技术,分享HTML5+CSS3的一些东西出来,及正要学习 数据结构与算法。2013年9月份左右在博客园有了自己的博客,时间匆匆而过,在博客园快有半年了!嗨!最后也祝福大家早点回家过年!路上一路顺风!时间也不早了,我也要休息!明天还要上班,感觉最后一个星期时间过得很慢很慢!嗨!

DEMO下载:

 
 

JS列表的下拉菜单组件(仿美化控件select)的更多相关文章

  1. 详解Bootstrap下拉菜单组件

    bootstrap框架中的下拉菜单组件是一个独立的组件,根据不同的版本,他对应的文件: less 对应的源码文件为:dropdowns.less sass对应的源码文件为:_dropdowns.scs ...

  2. bootstrap的下拉菜单组件与导航条

    前期准备:bootstrap的css文件和js文件先引入 Bootstrap 组件-拉下菜单(class+js) 下拉菜单必需三级结构 <div class="dropdown&quo ...

  3. -第2章 JS方法实现下拉菜单显示和隐藏

    知识点 onmouseover 鼠标经过 onmouseout 鼠标移出 function 关键字 getElementsByTagName 获取一组标签 length 获取对象成员个数 思路 给一级 ...

  4. 微信小程序 - 下拉菜单组件

    使用: 1.导入组件 2.使用组件 3.数据传入 4. 获取数据(通过同步缓存,获取“choose”)- 发送到后端 点击下载:小程序-下拉组件.

  5. Java Swing实战(二)下拉菜单组件JComboBox及其事件监听

    接下来给"数据源配置"面板添加下拉框. /** * @author: lishuai * @date: 2018/11/26 13:51 */ public class Weimi ...

  6. js二级导航下拉菜单

    <!DOCTYPE html> <html> <head> <title>导航列表</title> <meta http-equiv= ...

  7. 一个css和js结合的下拉菜单,支持主流浏览器

    首先声明: 本人尽管在web前端岗位干了好多年,但无奈岗位对技术要求不高.html,css用的比較多,JavaScript自己原创的非常少,基本都是copy改动,所以自己真正动手写时,发现基础非常不坚 ...

  8. js代码实现下拉菜单

    效果 js代码: <script type="text/javascript"> function ShowSub(li) {//函数定义 var subMenu = ...

  9. JS CSS写下拉菜单 竖行

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. windows平台搭建lighttpd+php+sqlite

    (一)php 1. 下载及安装 http://www.appservnetwork.com/ 从上面的网址下载appserv-win32-2.5.10并安装,在安装的时候,仅仅选择安装php. 由于, ...

  2. 深入了解Libgdx中间Skin分类

    文不是直接翻译.. . 本文在Libgdx的官方wiki的基础上,加上一些自己的理解.所以,难免会一些甚至是非常多的理解非常片面的东西.写的不好,还请见谅.... 事实上 事实上.在LibGDX的官方 ...

  3. 十天学Linux内核之第七天---电源开和关时都发生了什么

    原文:十天学Linux内核之第七天---电源开和关时都发生了什么 说实话感觉自己快写不下去了,其一是有些勉强跟不上来,其二是感觉自己越写越差,刚开始可能是新鲜感以及很多读者的鼓励,现在就是想快点完成自 ...

  4. Hadoop它——跑start-all.sh时间namenode不启动

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46353211 近期遇到了一个问题,运行start-all.sh的时候发现JPS一下 ...

  5. SQL Server编程系列(2):SMO常用对象的有关操作

    原文:SQL Server编程系列(2):SMO常用对象的有关操作 在上一篇周公简单讲述了SMO的一些基本概念,实际上SMO体系结构远不止周公在上一篇中讲述的那么简单,下图是MSDN上给出的一个完整的 ...

  6. HTML5使用和实战分析HTML5 WebSocket API

    通过引入一个简单的界面(请参见下面的列表),开发替代技术,由于长轮询和"永远框架,从而进一步减少延迟. 后台代码 [Constructor(in DOMString url, optiona ...

  7. DFS-hdu-2821-Pusher

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2821 题目意思: 给一个n*n的矩阵,里面有些位置是空的,有些位置有箱子(a代表一个箱子,b代表两个 ...

  8. JavaScript语法细节——引用与复制

    原文:JavaScript语法细节--引用与复制 我们都知道,JS中变量的赋值有两种方式,最近在折腾自己写的标签栏插件,碰到了很多平时没注意的问题.正好,那边处理清楚了,稍微整理一下关于引用与复制相关 ...

  9. vs2005中的WebBrowser控件的简单应用

    原文:vs2005中的WebBrowser控件的简单应用 这个控件被封装了一下,和以前的调用方式稍有不同.事件还是那几个,变化不大.方法变了不少.从网上能查到的资料不多,贴出一些代码来作参考.看看这段 ...

  10. linux perm

    转自: http://www.linuxidc.com/Linux/2012-05/59693.htm 有修改 nd -perm,根据文件的权限来查找文件,有三种形式:find -perm modef ...