最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
angularjs实现带查找筛选功能的select下拉框实例
时间:2017-01-12 编辑:简简单单 来源:一聚教程网
一.背景
对于select的下拉列表,像国家选择这样的功能,全世界那么多国家,一直拉滚动条多辛苦,眼睛也要盯着找,累!so,为优化用户体验,带查找功能的下拉框是非常非常有必要的。都知道jquery里有这样的插件,但我们用的是Angularjs,更希望用双向绑定,指令的方式优雅地解决这个问题。
分析:
目标 | 在原来的 |
问题 |
1.在selectSearch指令里,怎么获取到ng-options里的数据源,以及指定的value(option标签的value)和text(option标签里的text)字段名。 2.用什么方式来筛选?是每次显示匹配项,隐藏不匹配项还是?按未邮?菰蠢锲ヅ洌?匦律?山岬恪?/p> |
思路 |
1.参考angular自带指令ng-options来获取数据源和value,text字段名。 特别说明,仅支持ng-options="obj.value as obj.text for obj in list"的普通形式,那些带分组的等等,暂不支持哈。 2.重新生成结点。(为什么这么选择,方便呀!) |
二.具体实现
1.代码部分
1.1 js代码(请引先引入jquery,不然会报错)
代码如下 | 复制代码 |
/**
* 带筛选功能的下拉框
* 使用方法
* 说明[ select 一定要有name,ng-options 属性]
*/
.directive('ngcSelectSearch',function($animate, $compile, $parse) {
functionparseOptions(optionsExp, element, scope) {
// ngOptions里的正则
varNG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
varmatch = optionsExp.match(NG_OPTIONS_REGEXP);
if(!(match)) {
console.log('ng-options 表达式有误')
}
varvalueName = match[5] || match[7];
varkeyName = match[6];
vardisplayFn = $parse(match[2]);
varkeyFn = $parse(match[1]);
varvaluesFn = $parse(match[8]);
varlabelArray = [],
idArray = [],
optionValues = [];
scope.$watch(match[8],function(newValue, oldValue) {
if(newValue && newValue.length > 0) {
optionValues = valuesFn(scope) || [];
labelArray = [];
idArray = []
for(varindex = 0, l = optionValues.length; index < l; index++) {
varit = optionValues[index];
if(match[2] && match[1]) {
varlocalIt = {};
localIt[valueName] = it;
varlabel = displayFn(scope, localIt);
vardataId = keyFn(scope, localIt);
labelArray.push(label);
idArray.push(dataId);
}
}
scope.options = {
'optionValues': optionValues,
'labelArray': labelArray,
'idArray': idArray
}
}
});
}
return{
restrict:'A',
require: ['ngModel'],
priority: 100,
replace:false,
scope:true,
template:'
'+
'
'+ '
'+
'
'+
''+
' '+ '
// '
''+
' '+ ' ', link: {
pre:functionselectSearchPreLink(scope, element, attr, ctrls) {
vartmplNode = $(this.template).first();
varmodelName = attr.ngModel,
name = attr.name? attr.name:('def'+Date.now());
tmplNode.attr('id', name +'_chosecontianer');
$animate.enter(tmplNode, element.parent(), element);
},
post:functionselectSearchPostLink(scope, element, attr, ctrls) {
varchoseNode = element.next();//$('#'+attr.name +'_chosecontianer');
choseNode.addClass(attr.class);
element.addClass('chose-hide');
// 当前选中项
varngModelCtrl = ctrls[0];
if(!ngModelCtrl || !attr.name)return;
parseOptions(attr.ngOptions, element, scope);
varrs = {};
functionsetView() {
varcurrentKey = ngModelCtrl.$modelValue;
if(isNaN(currentKey) || !currentKey) {
currentKey ='';
choseNode.find('.j-view:first').text('请选择');
choseNode.find('i').addClass('chose-hide');
}
if((currentKey +'').length > 0) {
for(vari = 0, l = rs.idArray.length; i < l; i++) {
if(rs.idArray[i] == currentKey) {
choseNode.find('.j-view:first').text(rs.labelArray[i]);
choseNode.find('i').removeClass('chose-hide');
break;
}
}
}
}
functionsetViewAndData() {
if(!scope.options) {
return;
}
rs = scope.options;
setView();
}
scope.$watchCollection('options', setViewAndData);
scope.$watch(attr.ngModel, setView);
functiongetListNodes(value) {
varnodes = [];
value = $.trim(value);
for(vari = 0, l = rs.labelArray.length; i < l; i++) {
if(rs.labelArray[i].indexOf(value) > -1) {
nodes.push($('
}
}
returnnodes;
}
choseNode.on('keyup','.j-key',function() {
// 搜索输入框keyup,重新筛选列表
varvalue = $(this).val();
choseNode.find('ul:first').empty().append(getListNodes(value));
returnfalse;
}).on('click',function() {
choseNode.find('.j-drop').removeClass('chose-hide');
if(choseNode.find('.j-view:first').text() !='请选择') {
choseNode.find('i').removeClass('chose-hide');
}
choseNode.find('ul:first').empty().append(getListNodes(choseNode.find('.j-key').val()));
returnfalse;
}).on('click','ul>li',function() {
var_this = $(this);
ngModelCtrl.$setViewValue(_this.data('id'));
ngModelCtrl.$render();
choseNode.find('.j-drop').addClass('chose-hide');
returnfalse;
}).on('click','i',function() {
ngModelCtrl.$setViewValue('');
ngModelCtrl.$render();
choseNode.find('.j-view:first').text('请选择');
returnfalse;
});
$(document).on("click",function() {
$('.j-drop').addClass('chose-hide');
choseNode.find('i').addClass('chose-hide');
returnfalse;
});
}
}
};
})
|
1.2 css代码(用less写的,以下是编译后的)
代码如下 | 复制代码 |
.chose-hide{
position:absolute!important;
top:-999em!important;
}
.chose-container {
border:none!important;
float:left;
margin-right:40px;
padding:0!important;
position:relative;
}
.chose-container .chose-single {
padding:6px12px;
color:#333;
width:100%;
border:1pxsolid#eee;
display: inline-block;
height:30px;
}
.chose-container .chose-single::after {
content:'';
position:absolute;
border-width:6px3px;
border-style:solid;
/* border-top-color: transparent; */
border-left-color:transparent;
border-right-color:transparent;
border-bottom-color:transparent;
right:8px;
top:12px;
}
.chose-container .chose-single i {
width:12px;
float:right;
right:8px;
font-size:12px;
height:12px;
background-color:#eee;
}
.chose-container .chose-drop {
width:195px;
position:absolute;
border:1pxsolid#eee;
z-index:1000;
background-color:#fff;
}
.chose-container .chose-search input[type='text'] {
margin:0;
padding-left:12px;
width:100%;
height:30px;
border:1pxsolid#ccc;
float:none;
}
.chose-container .chose-result {
max-height:370px;
overflow-y:scroll;
overflow-x:hidden;
}
.chose-container .chose-result li {
padding:5px12px;
list-style-type:none;
}
.chose-container .chose-result li:hover {
background-color:#e1e2e7;
}
|
1.3 使用及效果
代码如下 | 复制代码 |
|
2.详细说明
程序中的关键点是parseOptions函数,即前面分析里的问题1。parseOptions是参考ng-options的源码实现的,原来是想返回一个对象,这个对象里包含了数据源,但是在调试时,发现post函数中该函数返回对象里的数据为空,watch不到,所以改为用scope.options来存数据。
-
上一个: 2017年网页设计的十大趋势
-
下一个: jQuery实现限制文本框的输入长度
相关文章
- HTML简单购物数量小程序代码展示 10-31
- html canvas实现弹幕功能 10-31
- HTML中空格表示的意义 10-31
- html area标签解读 10-31
- html使用表单标签实现注册页面代码展示 10-31
- 使用HTML截图并保存为本地图片的代码展示 10-31