mirror of https://github.com/layui/layui
feat(form-select): 支持创建新 option (#1618)
* feat(form-select): 支持创建新 option * docs: 更新 select 文档 * fix: escape * fix: 比较 option 未区分大小写 * update code * docs: form * fix: 缺少闭合标签 * fix: 删除 escape, 和初始 <dd> 行为一致pull/1682/head
parent
cecf33a83d
commit
18ac6d58f8
|
@ -117,6 +117,7 @@ form 还可以借助*栅格*实现更灵活的响应式布局。
|
|||
| lay-affix | [#详见](input.html#affix) | 输入框动态点缀,`<input type="text">`元素 **私有属性** |
|
||||
| lay-skin | [#详见](checkbox.html#default) | 设置 UI 风格。 `<input type="checkbox">` 元素 **私有属性** |
|
||||
| lay-search | 默认不区分大小写;<br>设置`cs`区分大小写 | 给 `select` 组件开启搜索功能。`<select>` 元素 **私有属性** |
|
||||
| lay-creatable <sup>2.9.7+</sup> | 无需值 | 是否允许创建新条目,需要配合 `lay-search` 使用。`<select>` 元素 **私有属性** } |
|
||||
| lay-submit | 无需值 | 设置元素(一般为`<button>` 标签)触发 `submit` 提交事件 |
|
||||
| lay-ignore | 无需值 | 设置表单元素忽略渲染,即让元素保留系统原始 UI 风格 |
|
||||
|
||||
|
|
|
@ -161,6 +161,18 @@ toc: true
|
|||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-col-md6">
|
||||
<select lay-search="" lay-creatable="">
|
||||
<option value="">可创建新的 option</option>
|
||||
<option value="1">AAA</option>
|
||||
<option value="2">aaa</option>
|
||||
<option value="3">BBB</option>
|
||||
<option value="4">bbb</option>
|
||||
<option value="5">ABC</option>
|
||||
<option value="6">abc</option>
|
||||
<option value="7">AbC</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- import layui -->
|
||||
|
|
|
@ -375,6 +375,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var CLASS = 'layui-form-select';
|
||||
var TITLE = 'layui-select-title';
|
||||
var NONE = 'layui-select-none';
|
||||
var CREATE_OPTION = 'layui-select-create-option';
|
||||
var initValue = '';
|
||||
var thatInput;
|
||||
var selects = elem || elemForm.find('select');
|
||||
|
@ -382,14 +383,18 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
// 隐藏 select
|
||||
var hide = function(e, clear){
|
||||
if(!$(e.target).parent().hasClass(TITLE) || clear){
|
||||
$('.'+CLASS).removeClass(CLASS+'ed ' + CLASS+'up');
|
||||
var elem = $('.' + CLASS);
|
||||
elem.removeClass(CLASS+'ed ' + CLASS+'up');
|
||||
if(elem.hasClass('layui-select-creatable')){
|
||||
elem.children('dl').children('.' + CREATE_OPTION).remove();
|
||||
}
|
||||
thatInput && initValue && thatInput.val(initValue);
|
||||
}
|
||||
thatInput = null;
|
||||
};
|
||||
|
||||
// 各种事件
|
||||
var events = function(reElem, disabled, isSearch){
|
||||
var events = function(reElem, disabled, isSearch, isCreatable){
|
||||
var select = $(this);
|
||||
var title = reElem.find('.' + TITLE);
|
||||
var input = title.find('input');
|
||||
|
@ -408,6 +413,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var showDown = function(){
|
||||
var top = reElem.offset().top + reElem.outerHeight() + 5 - $win.scrollTop();
|
||||
var dlHeight = dl.outerHeight();
|
||||
var dds = dl.children('dd');
|
||||
|
||||
index = select[0].selectedIndex; // 获取最新的 selectedIndex
|
||||
reElem.addClass(CLASS+'ed');
|
||||
|
@ -432,6 +438,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
reElem.removeClass(CLASS+'ed ' + CLASS+'up');
|
||||
input.blur();
|
||||
nearElem = null;
|
||||
isCreatable && dl.children('.' + CREATE_OPTION).remove();
|
||||
|
||||
if(choose) return;
|
||||
|
||||
|
@ -569,10 +576,18 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
// 检测值是否不属于 select 项
|
||||
var notOption = function(value, callback, origin){
|
||||
var num = 0;
|
||||
var dds = dl.children('dd');
|
||||
var hasEquals = false;
|
||||
var rawValue = value;
|
||||
layui.each(dds, function(){
|
||||
var othis = $(this);
|
||||
var text = othis.text();
|
||||
|
||||
// 需要区分大小写
|
||||
if(isCreatable && text === rawValue){
|
||||
hasEquals = true;
|
||||
}
|
||||
|
||||
// 是否区分大小写
|
||||
if(laySearch !== 'cs'){
|
||||
text = text.toLowerCase();
|
||||
|
@ -583,17 +598,18 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var not = text.indexOf(value) === -1;
|
||||
|
||||
if(value === '' || (origin === 'blur') ? value !== text : not) num++;
|
||||
origin === 'keyup' && othis[not ? 'addClass' : 'removeClass'](HIDE);
|
||||
origin === 'keyup' && othis[(not && (isCreatable ? !othis.hasClass(CREATE_OPTION) : true)) ? 'addClass' : 'removeClass'](HIDE);
|
||||
});
|
||||
// 处理 select 分组元素
|
||||
origin === 'keyup' && layui.each(dts, function(){
|
||||
var othis = $(this)
|
||||
,thisDds = othis.nextUntil('dt').filter('dd') // 当前分组下的dd元素
|
||||
,allHide = thisDds.length == thisDds.filter('.' + HIDE).length; // 当前分组下所有dd元素都隐藏了
|
||||
var othis = $(this);
|
||||
var thisDds = othis.nextUntil('dt').filter('dd'); // 当前分组下的dd元素
|
||||
if(isCreatable) thisDds = thisDds.not('.' + CREATE_OPTION);
|
||||
var allHide = thisDds.length == thisDds.filter('.' + HIDE).length; // 当前分组下所有dd元素都隐藏了
|
||||
othis[allHide ? 'addClass' : 'removeClass'](HIDE);
|
||||
});
|
||||
var none = num === dds.length;
|
||||
return callback(none), none;
|
||||
return callback(none, hasEquals), none;
|
||||
};
|
||||
|
||||
// 搜索匹配
|
||||
|
@ -607,11 +623,27 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
return false;
|
||||
}
|
||||
|
||||
notOption(value, function(none){
|
||||
if(none){
|
||||
dl.find('.'+NONE)[0] || dl.append('<p class="'+ NONE +'">无匹配项</p>');
|
||||
} else {
|
||||
dl.find('.'+NONE).remove();
|
||||
notOption(value, function(none, hasEquals){
|
||||
if(isCreatable){
|
||||
if(hasEquals){
|
||||
dl.children('.' + CREATE_OPTION).remove();
|
||||
}else{
|
||||
// 和初始渲染保持行为一致
|
||||
var textVal = $('<div>' + value +'</div>').text();
|
||||
var createOptionElem = dl.children('.' + CREATE_OPTION);
|
||||
if(createOptionElem[0]){
|
||||
createOptionElem.attr('lay-value', value);
|
||||
createOptionElem.text(textVal);
|
||||
}else{
|
||||
dl.append('<dd class="' + CREATE_OPTION + '" lay-value="'+ value +'">' + textVal + '</dd>');
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(none){
|
||||
dl.find('.'+NONE)[0] || dl.append('<p class="'+ NONE +'">无匹配项</p>');
|
||||
} else {
|
||||
dl.find('.'+NONE).remove();
|
||||
}
|
||||
}
|
||||
}, 'keyup');
|
||||
|
||||
|
@ -622,6 +654,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
dl.find('.'+ THIS).removeClass(THIS);
|
||||
(select[0].options[0] || {}).value || dl.children('dd:eq(0)').addClass(THIS);
|
||||
dl.find('.'+ NONE).remove();
|
||||
isCreatable && dl.children('.' + CREATE_OPTION).remove();
|
||||
}
|
||||
|
||||
followScroll(); // 定位滚动条
|
||||
|
@ -653,7 +686,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
}
|
||||
|
||||
// 选择
|
||||
dds.on('click', function(){
|
||||
dl.on('click', 'dd', function(){
|
||||
var othis = $(this), value = othis.attr('lay-value');
|
||||
var filter = select.attr('lay-filter'); // 获取过滤器
|
||||
|
||||
|
@ -666,6 +699,11 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
othis.addClass(THIS);
|
||||
}
|
||||
|
||||
if(isCreatable && othis.hasClass(CREATE_OPTION)){
|
||||
othis.removeClass(CREATE_OPTION);
|
||||
select.append('<option value="' + value + '">' + value + '</option>');
|
||||
}
|
||||
|
||||
othis.siblings().removeClass(THIS);
|
||||
select.val(value).removeClass('layui-form-danger');
|
||||
|
||||
|
@ -698,13 +736,15 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
if(typeof othis.attr('lay-ignore') === 'string') return othis.show();
|
||||
|
||||
var isSearch = typeof othis.attr('lay-search') === 'string'
|
||||
,isCreatable = typeof othis.attr('lay-creatable') === 'string' && isSearch
|
||||
,placeholder = optionsFirst ? (
|
||||
optionsFirst.value ? TIPS : (optionsFirst.innerHTML || TIPS)
|
||||
) : TIPS;
|
||||
|
||||
// 替代元素
|
||||
var reElem = $(['<div class="'+ (isSearch ? '' : 'layui-unselect ') + CLASS
|
||||
,(disabled ? ' layui-select-disabled' : '') +'">'
|
||||
,(disabled ? ' layui-select-disabled' : '')
|
||||
,(isCreatable ? ' layui-select-creatable' : '') + '">'
|
||||
,'<div class="'+ TITLE +'">'
|
||||
,('<input type="text" placeholder="'+ util.escape($.trim(placeholder)) +'" '
|
||||
+('value="'+ util.escape($.trim(value ? selected.html() : '')) +'"') // 默认值
|
||||
|
@ -734,7 +774,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
|
||||
hasRender[0] && hasRender.remove(); // 如果已经渲染,则Rerender
|
||||
othis.after(reElem);
|
||||
events.call(this, reElem, disabled, isSearch);
|
||||
events.call(this, reElem, disabled, isSearch, isCreatable);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue