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-affix | [#详见](input.html#affix) | 输入框动态点缀,`<input type="text">`元素 **私有属性** |
|
||||||
| lay-skin | [#详见](checkbox.html#default) | 设置 UI 风格。 `<input type="checkbox">` 元素 **私有属性** |
|
| lay-skin | [#详见](checkbox.html#default) | 设置 UI 风格。 `<input type="checkbox">` 元素 **私有属性** |
|
||||||
| lay-search | 默认不区分大小写;<br>设置`cs`区分大小写 | 给 `select` 组件开启搜索功能。`<select>` 元素 **私有属性** |
|
| lay-search | 默认不区分大小写;<br>设置`cs`区分大小写 | 给 `select` 组件开启搜索功能。`<select>` 元素 **私有属性** |
|
||||||
|
| lay-creatable <sup>2.9.7+</sup> | 无需值 | 是否允许创建新条目,需要配合 `lay-search` 使用。`<select>` 元素 **私有属性** } |
|
||||||
| lay-submit | 无需值 | 设置元素(一般为`<button>` 标签)触发 `submit` 提交事件 |
|
| lay-submit | 无需值 | 设置元素(一般为`<button>` 标签)触发 `submit` 提交事件 |
|
||||||
| lay-ignore | 无需值 | 设置表单元素忽略渲染,即让元素保留系统原始 UI 风格 |
|
| lay-ignore | 无需值 | 设置表单元素忽略渲染,即让元素保留系统原始 UI 风格 |
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,18 @@ toc: true
|
||||||
</optgroup>
|
</optgroup>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
<!-- import layui -->
|
<!-- import layui -->
|
||||||
|
|
|
@ -375,6 +375,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||||
var CLASS = 'layui-form-select';
|
var CLASS = 'layui-form-select';
|
||||||
var TITLE = 'layui-select-title';
|
var TITLE = 'layui-select-title';
|
||||||
var NONE = 'layui-select-none';
|
var NONE = 'layui-select-none';
|
||||||
|
var CREATE_OPTION = 'layui-select-create-option';
|
||||||
var initValue = '';
|
var initValue = '';
|
||||||
var thatInput;
|
var thatInput;
|
||||||
var selects = elem || elemForm.find('select');
|
var selects = elem || elemForm.find('select');
|
||||||
|
@ -382,14 +383,18 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||||
// 隐藏 select
|
// 隐藏 select
|
||||||
var hide = function(e, clear){
|
var hide = function(e, clear){
|
||||||
if(!$(e.target).parent().hasClass(TITLE) || 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 && initValue && thatInput.val(initValue);
|
||||||
}
|
}
|
||||||
thatInput = null;
|
thatInput = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 各种事件
|
// 各种事件
|
||||||
var events = function(reElem, disabled, isSearch){
|
var events = function(reElem, disabled, isSearch, isCreatable){
|
||||||
var select = $(this);
|
var select = $(this);
|
||||||
var title = reElem.find('.' + TITLE);
|
var title = reElem.find('.' + TITLE);
|
||||||
var input = title.find('input');
|
var input = title.find('input');
|
||||||
|
@ -408,6 +413,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||||
var showDown = function(){
|
var showDown = function(){
|
||||||
var top = reElem.offset().top + reElem.outerHeight() + 5 - $win.scrollTop();
|
var top = reElem.offset().top + reElem.outerHeight() + 5 - $win.scrollTop();
|
||||||
var dlHeight = dl.outerHeight();
|
var dlHeight = dl.outerHeight();
|
||||||
|
var dds = dl.children('dd');
|
||||||
|
|
||||||
index = select[0].selectedIndex; // 获取最新的 selectedIndex
|
index = select[0].selectedIndex; // 获取最新的 selectedIndex
|
||||||
reElem.addClass(CLASS+'ed');
|
reElem.addClass(CLASS+'ed');
|
||||||
|
@ -432,6 +438,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||||
reElem.removeClass(CLASS+'ed ' + CLASS+'up');
|
reElem.removeClass(CLASS+'ed ' + CLASS+'up');
|
||||||
input.blur();
|
input.blur();
|
||||||
nearElem = null;
|
nearElem = null;
|
||||||
|
isCreatable && dl.children('.' + CREATE_OPTION).remove();
|
||||||
|
|
||||||
if(choose) return;
|
if(choose) return;
|
||||||
|
|
||||||
|
@ -569,10 +576,18 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||||
// 检测值是否不属于 select 项
|
// 检测值是否不属于 select 项
|
||||||
var notOption = function(value, callback, origin){
|
var notOption = function(value, callback, origin){
|
||||||
var num = 0;
|
var num = 0;
|
||||||
|
var dds = dl.children('dd');
|
||||||
|
var hasEquals = false;
|
||||||
|
var rawValue = value;
|
||||||
layui.each(dds, function(){
|
layui.each(dds, function(){
|
||||||
var othis = $(this);
|
var othis = $(this);
|
||||||
var text = othis.text();
|
var text = othis.text();
|
||||||
|
|
||||||
|
// 需要区分大小写
|
||||||
|
if(isCreatable && text === rawValue){
|
||||||
|
hasEquals = true;
|
||||||
|
}
|
||||||
|
|
||||||
// 是否区分大小写
|
// 是否区分大小写
|
||||||
if(laySearch !== 'cs'){
|
if(laySearch !== 'cs'){
|
||||||
text = text.toLowerCase();
|
text = text.toLowerCase();
|
||||||
|
@ -583,17 +598,18 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||||
var not = text.indexOf(value) === -1;
|
var not = text.indexOf(value) === -1;
|
||||||
|
|
||||||
if(value === '' || (origin === 'blur') ? value !== text : not) num++;
|
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 分组元素
|
// 处理 select 分组元素
|
||||||
origin === 'keyup' && layui.each(dts, function(){
|
origin === 'keyup' && layui.each(dts, function(){
|
||||||
var othis = $(this)
|
var othis = $(this);
|
||||||
,thisDds = othis.nextUntil('dt').filter('dd') // 当前分组下的dd元素
|
var thisDds = othis.nextUntil('dt').filter('dd'); // 当前分组下的dd元素
|
||||||
,allHide = thisDds.length == thisDds.filter('.' + HIDE).length; // 当前分组下所有dd元素都隐藏了
|
if(isCreatable) thisDds = thisDds.not('.' + CREATE_OPTION);
|
||||||
|
var allHide = thisDds.length == thisDds.filter('.' + HIDE).length; // 当前分组下所有dd元素都隐藏了
|
||||||
othis[allHide ? 'addClass' : 'removeClass'](HIDE);
|
othis[allHide ? 'addClass' : 'removeClass'](HIDE);
|
||||||
});
|
});
|
||||||
var none = num === dds.length;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
notOption(value, function(none){
|
notOption(value, function(none, hasEquals){
|
||||||
if(none){
|
if(isCreatable){
|
||||||
dl.find('.'+NONE)[0] || dl.append('<p class="'+ NONE +'">无匹配项</p>');
|
if(hasEquals){
|
||||||
} else {
|
dl.children('.' + CREATE_OPTION).remove();
|
||||||
dl.find('.'+NONE).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');
|
}, 'keyup');
|
||||||
|
|
||||||
|
@ -622,6 +654,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||||
dl.find('.'+ THIS).removeClass(THIS);
|
dl.find('.'+ THIS).removeClass(THIS);
|
||||||
(select[0].options[0] || {}).value || dl.children('dd:eq(0)').addClass(THIS);
|
(select[0].options[0] || {}).value || dl.children('dd:eq(0)').addClass(THIS);
|
||||||
dl.find('.'+ NONE).remove();
|
dl.find('.'+ NONE).remove();
|
||||||
|
isCreatable && dl.children('.' + CREATE_OPTION).remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
followScroll(); // 定位滚动条
|
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 othis = $(this), value = othis.attr('lay-value');
|
||||||
var filter = select.attr('lay-filter'); // 获取过滤器
|
var filter = select.attr('lay-filter'); // 获取过滤器
|
||||||
|
|
||||||
|
@ -666,6 +699,11 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||||
othis.addClass(THIS);
|
othis.addClass(THIS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isCreatable && othis.hasClass(CREATE_OPTION)){
|
||||||
|
othis.removeClass(CREATE_OPTION);
|
||||||
|
select.append('<option value="' + value + '">' + value + '</option>');
|
||||||
|
}
|
||||||
|
|
||||||
othis.siblings().removeClass(THIS);
|
othis.siblings().removeClass(THIS);
|
||||||
select.val(value).removeClass('layui-form-danger');
|
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();
|
if(typeof othis.attr('lay-ignore') === 'string') return othis.show();
|
||||||
|
|
||||||
var isSearch = typeof othis.attr('lay-search') === 'string'
|
var isSearch = typeof othis.attr('lay-search') === 'string'
|
||||||
|
,isCreatable = typeof othis.attr('lay-creatable') === 'string' && isSearch
|
||||||
,placeholder = optionsFirst ? (
|
,placeholder = optionsFirst ? (
|
||||||
optionsFirst.value ? TIPS : (optionsFirst.innerHTML || TIPS)
|
optionsFirst.value ? TIPS : (optionsFirst.innerHTML || TIPS)
|
||||||
) : TIPS;
|
) : TIPS;
|
||||||
|
|
||||||
// 替代元素
|
// 替代元素
|
||||||
var reElem = $(['<div class="'+ (isSearch ? '' : 'layui-unselect ') + CLASS
|
var reElem = $(['<div class="'+ (isSearch ? '' : 'layui-unselect ') + CLASS
|
||||||
,(disabled ? ' layui-select-disabled' : '') +'">'
|
,(disabled ? ' layui-select-disabled' : '')
|
||||||
|
,(isCreatable ? ' layui-select-creatable' : '') + '">'
|
||||||
,'<div class="'+ TITLE +'">'
|
,'<div class="'+ TITLE +'">'
|
||||||
,('<input type="text" placeholder="'+ util.escape($.trim(placeholder)) +'" '
|
,('<input type="text" placeholder="'+ util.escape($.trim(placeholder)) +'" '
|
||||||
+('value="'+ util.escape($.trim(value ? selected.html() : '')) +'"') // 默认值
|
+('value="'+ util.escape($.trim(value ? selected.html() : '')) +'"') // 默认值
|
||||||
|
@ -734,7 +774,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
||||||
|
|
||||||
hasRender[0] && hasRender.remove(); // 如果已经渲染,则Rerender
|
hasRender[0] && hasRender.remove(); // 如果已经渲染,则Rerender
|
||||||
othis.after(reElem);
|
othis.after(reElem);
|
||||||
events.call(this, reElem, disabled, isSearch);
|
events.call(this, reElem, disabled, isSearch, isCreatable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue