mirror of https://github.com/layui/layui
fix(form): 修复 select 组件的字符转义问题 (#2661)
* fix(form): 修复 select 组件的字符转义问题 * Update src/modules/form.js Co-authored-by: morning-star <26325820+Sight-wcg@users.noreply.github.com> --------- Co-authored-by: morning-star <26325820+Sight-wcg@users.noreply.github.com>2.9.x-stable
parent
467a8de205
commit
0a80e99024
|
@ -6,7 +6,7 @@
|
|||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
|
||||
|
@ -140,7 +140,7 @@
|
|||
<div class="layui-col-md12">
|
||||
<button class="layui-btn" id="testSubmit">立即提交</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
@ -163,7 +163,7 @@
|
|||
<div class="layui-input-inline">
|
||||
<input type="text" name="vercode" lay-verify="required" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid" style="padding: 0!important;">
|
||||
<div class="layui-form-mid" style="padding: 0!important;">
|
||||
<button type="button" class="layui-btn layui-btn-primary" lay-on="get-vercode">获取验证码</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -200,8 +200,8 @@
|
|||
<div class="layui-inline">
|
||||
<label class="layui-form-label">行内表单</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="quiz" lay-verify="required" lay-vertype="tips" lay-filter="quiz111">
|
||||
<option value="">请"选择"问题</option>
|
||||
<select name="quiz" lay-verify="required" lay-vertype="tips" lay-filter="quiz">
|
||||
<option value="">请"选择"问题 😀</option>
|
||||
<option value="0">你工"作"的 第一个城市</option>
|
||||
<option value="1" disabled>你的工号</option>
|
||||
<option value="2">
|
||||
|
@ -213,7 +213,7 @@
|
|||
<div class="layui-inline">
|
||||
<label class="layui-form-label">select分组</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="quiz" lay-filter="quiz">
|
||||
<select name="quiz111" lay-filter="quiz111">
|
||||
<option value="">请选择问题</option>
|
||||
<optgroup label="城市记忆">
|
||||
<option value="0">你工作的第一个城市</option>
|
||||
|
@ -226,7 +226,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">选择框</label>
|
||||
<div class="layui-input-block">
|
||||
|
@ -240,12 +240,12 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">搜索选择框</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="interest-search" lay-filter="interest-search" lay-search="">
|
||||
<select name="interest-search" lay-filter="interest-search" lay-search="" lay-creatable>
|
||||
<option value="">请搜索</option>
|
||||
<option value="写作">写"作"</option>
|
||||
<option value="阅读" disabled>阅读</option>
|
||||
|
@ -309,7 +309,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="layui-form-item" pane>
|
||||
<label class="layui-form-label">复选框</label>
|
||||
<div class="layui-input-block">
|
||||
|
@ -398,14 +398,14 @@
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
form.on('submit(top)', function(data){
|
||||
console.log(data);
|
||||
return false;
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
//方法提交
|
||||
$('#testSubmit').on('click', function(){
|
||||
form.submit('top', function(data){
|
||||
|
@ -416,18 +416,18 @@
|
|||
setTimeout(function(){
|
||||
alert(JSON.stringify(data.field));
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
//日期
|
||||
laydate.render({
|
||||
elem: '#date'
|
||||
});
|
||||
|
||||
|
||||
//初始赋值
|
||||
var thisValue = form.val('first', {
|
||||
'title': '测试测试测试'
|
||||
|
@ -449,32 +449,32 @@
|
|||
var elem = data.elem;
|
||||
elem.value = '通过自定义事件设置的值';
|
||||
});
|
||||
|
||||
|
||||
//事件
|
||||
form.on('select(quiz111)', function(data){
|
||||
console.log('select: ', this, data);
|
||||
});
|
||||
|
||||
form.on('select(quiz)', function(data){
|
||||
console.log('select.quiz:', this, data);
|
||||
console.log('select.quiz: ', this, data);
|
||||
});
|
||||
|
||||
|
||||
form.on('select(quiz111)', function(data){
|
||||
console.log('select.quiz111:', this, data);
|
||||
});
|
||||
|
||||
form.on('select(interest)', function(data){
|
||||
console.log('select.interest: ', this, data);
|
||||
});
|
||||
|
||||
|
||||
form.on('checkbox', function(data){
|
||||
console.log(this.checked, data.elem.checked);
|
||||
});
|
||||
|
||||
|
||||
form.on('switch', function(data){
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
|
||||
form.on('radio', function(data){
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
|
||||
// 提交事件
|
||||
form.on('submit(*)', function(data){
|
||||
console.log(data)
|
||||
|
@ -497,12 +497,51 @@
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<h3>设置 lay-ignore 忽略渲染</h3>
|
||||
<hr>
|
||||
<div class="layui-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">未设置 ignore 时:</div>
|
||||
<div class="layui-inline">
|
||||
<input type="checkbox" name="like[write]" title="checkbox">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">忽略指令直接设置:</div>
|
||||
<div class="layui-inline">
|
||||
<input type="checkbox" name="like[write]" lay-ignore title="写作">
|
||||
<input type="radio" name="sex" value="1" lay-ignore title="男">
|
||||
<select name="quiz" lay-ignore>
|
||||
<option value="">请选择</option>
|
||||
<option value="AAAAA" selected>AAAAA</option>
|
||||
<option value="BBBBB">BBBBB</option>
|
||||
<option value="CCCCC">CCCCC</option>
|
||||
<option value="DDDDD" disabled>DDDDD</option>
|
||||
<option value="EEEEE">EEEEE</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">忽略指令父元素设置:</div>
|
||||
<div class="layui-inline" lay-ignore>
|
||||
<input type="checkbox" name="like[write]" title="写作">
|
||||
<input type="radio" name="sex" value="1" title="男">
|
||||
<select name="quiz111">
|
||||
<option value="">请选择</option>
|
||||
<option value="AAAAA">AAAAA</option>
|
||||
<option value="BBBBB">BBBBB</option>
|
||||
<option value="CCCCC" selected>CCCCC</option>
|
||||
<option value="DDDDD" disabled>DDDDD</option>
|
||||
<option value="EEEEE">EEEEE</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>原始表单调试:</h3>
|
||||
<hr>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
/**
|
||||
* form 表单组件
|
||||
*/
|
||||
|
||||
|
||||
layui.define(['lay', 'layer', 'util'], function(exports){
|
||||
"use strict";
|
||||
|
||||
|
||||
var $ = layui.$;
|
||||
var layer = layui.layer;
|
||||
var util = layui.util;
|
||||
var hint = layui.hint();
|
||||
var device = layui.device();
|
||||
var needCheckboxFallback = lay.ie && parseFloat(lay.ie) === 8;
|
||||
|
||||
|
||||
var MOD_NAME = 'form';
|
||||
var ELEM = '.layui-form';
|
||||
var THIS = 'layui-this';
|
||||
|
@ -19,7 +19,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var HIDE = 'layui-hide';
|
||||
var DISABLED = 'layui-disabled';
|
||||
var OUT_OF_RANGE = 'layui-input-number-out-of-range';
|
||||
|
||||
|
||||
var Form = function(){
|
||||
this.config = {
|
||||
// 内置的验证规则
|
||||
|
@ -68,14 +68,14 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
autocomplete: null // 全局 autocomplete 状态。 null 表示不干预
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// 全局设置
|
||||
Form.prototype.set = function(options){
|
||||
var that = this;
|
||||
$.extend(true, that.config, options);
|
||||
return that;
|
||||
};
|
||||
|
||||
|
||||
// 验证规则设定
|
||||
Form.prototype.verify = function(settings){
|
||||
var that = this;
|
||||
|
@ -89,21 +89,21 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
return filter ? ('[lay-filter="' + filter +'"]') : '';
|
||||
}());
|
||||
};
|
||||
|
||||
|
||||
// 表单事件
|
||||
Form.prototype.on = function(events, callback){
|
||||
return layui.onevent.call(this, MOD_NAME, events, callback);
|
||||
};
|
||||
|
||||
|
||||
// 赋值/取值
|
||||
Form.prototype.val = function(filter, object){
|
||||
var that = this
|
||||
,formElem = that.getFormElem(filter);
|
||||
|
||||
|
||||
// 遍历
|
||||
formElem.each(function(index, item){
|
||||
var itemForm = $(this);
|
||||
|
||||
|
||||
// 赋值
|
||||
for(var key in object){
|
||||
if(!lay.hasOwn(object, key)) continue;
|
||||
|
@ -111,11 +111,11 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var type;
|
||||
var value = object[key];
|
||||
var itemElem = itemForm.find('[name="'+ key +'"]');
|
||||
|
||||
|
||||
// 如果对应的表单不存在,则不执行
|
||||
if(!itemElem[0]) continue;
|
||||
type = itemElem[0].type;
|
||||
|
||||
|
||||
// 如果为复选框
|
||||
if(type === 'checkbox'){
|
||||
itemElem[0].checked = value;
|
||||
|
@ -128,47 +128,47 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
form.render(null, filter);
|
||||
|
||||
|
||||
// 返回值
|
||||
return that.getValue(filter);
|
||||
};
|
||||
|
||||
|
||||
// 取值
|
||||
Form.prototype.getValue = function(filter, itemForm){
|
||||
itemForm = itemForm || this.getFormElem(filter);
|
||||
|
||||
|
||||
var nameIndex = {} // 数组 name 索引
|
||||
,field = {}
|
||||
,fieldElem = itemForm.find('input,select,textarea') // 获取所有表单域
|
||||
|
||||
layui.each(fieldElem, function(_, item){
|
||||
|
||||
layui.each(fieldElem, function(_, item){
|
||||
var othis = $(this)
|
||||
,init_name; // 初始 name
|
||||
|
||||
|
||||
item.name = (item.name || '').replace(/^\s*|\s*&/, '');
|
||||
if(!item.name) return;
|
||||
|
||||
|
||||
// 用于支持数组 name
|
||||
if(/^.*\[\]$/.test(item.name)){
|
||||
var key = item.name.match(/^(.*)\[\]$/g)[0];
|
||||
nameIndex[key] = nameIndex[key] | 0;
|
||||
init_name = item.name.replace(/^(.*)\[\]$/, '$1['+ (nameIndex[key]++) +']');
|
||||
}
|
||||
|
||||
if(/^(checkbox|radio)$/.test(item.type) && !item.checked) return; // 复选框和单选框未选中,不记录字段
|
||||
|
||||
if(/^(checkbox|radio)$/.test(item.type) && !item.checked) return; // 复选框和单选框未选中,不记录字段
|
||||
// select 多选用 jQuery 方式取值,未选中 option 时,
|
||||
// jQuery v2.2.4 及以下版本返回 null,以上(3.x) 返回 []。
|
||||
// 统一规范化为 [],参考 https://github.com/jquery/jquery/issues/2562
|
||||
field[init_name || item.name] = (this.tagName === 'SELECT' && typeof this.getAttribute('multiple') === 'string')
|
||||
field[init_name || item.name] = (this.tagName === 'SELECT' && typeof this.getAttribute('multiple') === 'string')
|
||||
? othis.val() || []
|
||||
: this.value;
|
||||
});
|
||||
|
||||
|
||||
return field;
|
||||
};
|
||||
|
||||
|
||||
// 表单控件渲染
|
||||
Form.prototype.render = function(type, filter){
|
||||
var that = this;
|
||||
|
@ -273,7 +273,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
});
|
||||
return arr.join('');
|
||||
}());
|
||||
|
||||
|
||||
elemAffix.append(elemIcon); // 插入图标元素
|
||||
|
||||
// 追加 className
|
||||
|
@ -298,8 +298,8 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
hasElemSuffix.prepend(elemAffix);
|
||||
|
||||
othis.css('padding-right', function(){
|
||||
var paddingRight = othis.closest('.layui-input-group')[0]
|
||||
? 0
|
||||
var paddingRight = othis.closest('.layui-input-group')[0]
|
||||
? 0
|
||||
: hasElemSuffix.outerWidth();
|
||||
return paddingRight + elemAffix.outerWidth()
|
||||
});
|
||||
|
@ -309,9 +309,9 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
}
|
||||
|
||||
opts.show === 'auto' && showAffix(elemAffix, othis.val());
|
||||
|
||||
|
||||
typeof opts.init === 'function' && opts.init.call(this, othis, opts);
|
||||
|
||||
|
||||
// 输入事件
|
||||
othis.on('input propertychange', function(){
|
||||
var value = this.value;
|
||||
|
@ -322,14 +322,14 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
othis.on('blur', function(){
|
||||
typeof opts.blur === 'function' && opts.blur.call(this, othis, opts);
|
||||
});
|
||||
|
||||
|
||||
// 点击动态后缀事件
|
||||
elemIcon.on('click', function(){
|
||||
var inputFilter = othis.attr('lay-filter');
|
||||
if($(this).hasClass(DISABLED)) return;
|
||||
|
||||
|
||||
typeof opts.click === 'function' && opts.click.call(this, othis, opts);
|
||||
|
||||
|
||||
// 对外事件
|
||||
layui.event.call(this, MOD_NAME, 'input-affix('+ inputFilter +')', {
|
||||
elem: othis[0],
|
||||
|
@ -338,7 +338,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 动态点缀配置项
|
||||
var affixOptions = {
|
||||
eye: { // 密码显隐
|
||||
|
@ -346,7 +346,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
click: function(elem, opts){ // 事件
|
||||
var SHOW_NAME = 'LAY_FORM_INPUT_AFFIX_SHOW';
|
||||
var isShow = elem.data(SHOW_NAME);
|
||||
|
||||
|
||||
elem.attr('type', isShow ? 'password' : 'text').data(SHOW_NAME, !isShow);
|
||||
|
||||
renderAffix({
|
||||
|
@ -379,11 +379,11 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
renderAffix();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 下拉选择框
|
||||
,select: function(elem){
|
||||
var TIPS = '请选择';
|
||||
|
@ -406,11 +406,11 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var index = this.selectedIndex; // 当前选中的索引
|
||||
var initValue = '';
|
||||
var removeClickOutsideEvent;
|
||||
|
||||
|
||||
if(disabled) return;
|
||||
|
||||
/**
|
||||
* 搜索项
|
||||
* 搜索项
|
||||
* @typedef searchOption
|
||||
* @prop {boolean} [caseSensitive=false] 是否区分大小写
|
||||
* @prop {boolean} [fuzzy=false] 是否开启模糊匹配,开启后将会忽略模式出现在字符串中的位置。
|
||||
|
@ -425,7 +425,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
// IE10 和 11 中,带有占位符的 input 元素获得/失去焦点时,会触发 input 事件
|
||||
// 当鼠标按下时,根据 input 元素上的 __ieph 标识忽略 input 事件
|
||||
var needPlaceholderPatch = !!(lay.ie && (lay.ie === '10' || lay.ie === '11') && input.attr('placeholder'));
|
||||
|
||||
|
||||
// 展开下拉
|
||||
var showDown = function(){
|
||||
if(isAppendTo){
|
||||
|
@ -446,7 +446,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var top = reElem.offset().top + reElem.outerHeight() + 5 - $win.scrollTop();
|
||||
var dlHeight = dl.outerHeight();
|
||||
var dds = dl.children('dd');
|
||||
|
||||
|
||||
index = select[0].selectedIndex; // 获取最新的 selectedIndex
|
||||
title.parent().addClass(CLASS+'ed');
|
||||
dds.removeClass(HIDE);
|
||||
|
@ -481,7 +481,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
{ignore: title}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// 隐藏下拉
|
||||
var hideDown = function(choose){
|
||||
title.parent().removeClass(CLASS+'ed ' + CLASS+'up');
|
||||
|
@ -492,16 +492,16 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
reElem.detach();
|
||||
$(window).off('resize.lay_select_resize');
|
||||
}
|
||||
|
||||
|
||||
if(choose) return;
|
||||
|
||||
|
||||
notOption(input.val(), function(none){
|
||||
var selectedIndex = select[0].selectedIndex;
|
||||
|
||||
|
||||
// 未查询到相关值
|
||||
if(none){
|
||||
initValue = $(select[0].options[selectedIndex]).html(); // 重新获得初始选中值
|
||||
|
||||
initValue = $(select[0].options[selectedIndex]).text(); // 重新获得初始选中值
|
||||
|
||||
// 如果是第一项,且文本值等于 placeholder,则清空初始值
|
||||
if(selectedIndex === 0 && initValue === input.attr('placeholder')){
|
||||
initValue = '';
|
||||
|
@ -512,28 +512,28 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 定位下拉滚动条
|
||||
var followScroll = function(){
|
||||
var followScroll = function(){
|
||||
var thisDd = dl.children('dd.'+ THIS);
|
||||
|
||||
|
||||
if(!thisDd[0]) return;
|
||||
|
||||
|
||||
var posTop = thisDd.position().top;
|
||||
var dlHeight = dl.height();
|
||||
var ddHeight = thisDd.height();
|
||||
|
||||
|
||||
// 若选中元素在滚动条不可见底部
|
||||
if(posTop > dlHeight){
|
||||
dl.scrollTop(posTop + dl.scrollTop() - dlHeight + ddHeight - 5);
|
||||
}
|
||||
|
||||
|
||||
// 若选择元素在滚动条不可见顶部
|
||||
if(posTop < 0){
|
||||
dl.scrollTop(posTop + dl.scrollTop() - 5);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 点击标题区域
|
||||
title.on('click', function(e){
|
||||
title.parent().hasClass(CLASS+'ed') ? (
|
||||
|
@ -542,17 +542,17 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
showDown()
|
||||
);
|
||||
dl.find('.'+NONE).remove();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// 点击箭头获取焦点
|
||||
title.find('.layui-edge').on('click', function(){
|
||||
input.focus();
|
||||
});
|
||||
|
||||
|
||||
// select 中 input 键盘事件
|
||||
input.on('keyup', function(e){ // 键盘松开
|
||||
var keyCode = e.keyCode;
|
||||
|
||||
|
||||
// Tab键展开
|
||||
if(keyCode === 9){
|
||||
showDown();
|
||||
|
@ -564,7 +564,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
if(keyCode === 9){
|
||||
hideDown();
|
||||
}
|
||||
|
||||
|
||||
// 标注 dd 的选中状态
|
||||
var setThisDd = function(prevNext){
|
||||
e.preventDefault();
|
||||
|
@ -580,7 +580,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
return true;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
var nextIndex = prevNext === 'prev'
|
||||
? (selectedIndex - 1 < firstIndex ? lastIndex : selectedIndex - 1)
|
||||
: (selectedIndex + 1 > lastIndex ? firstIndex : selectedIndex + 1)
|
||||
|
@ -589,19 +589,19 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
selectedElem.addClass(THIS).siblings().removeClass(THIS); // 标注样式
|
||||
followScroll(); // 定位滚动条
|
||||
};
|
||||
|
||||
|
||||
if(keyCode === 38) setThisDd('prev'); // Up 键
|
||||
if(keyCode === 40) setThisDd('next'); // Down 键
|
||||
|
||||
|
||||
// Enter 键
|
||||
if(keyCode === 13){
|
||||
if(keyCode === 13){
|
||||
e.preventDefault();
|
||||
dl.children('dd.'+THIS).trigger('click');
|
||||
}
|
||||
}).on('paste', function(){
|
||||
showDown();
|
||||
});
|
||||
|
||||
|
||||
// 检测值是否不属于 select 项
|
||||
var notOption = function(value, callback, origin){
|
||||
var num = 0;
|
||||
|
@ -629,10 +629,10 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
if(!laySearch.caseSensitive){
|
||||
text = text.toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
// 匹配
|
||||
var not = laySearch.fuzzy ? !fuzzyMatchRE.test(text) : text.indexOf(value) === -1;
|
||||
|
||||
|
||||
if(value === '' || (origin === 'blur') ? value !== text : not) num++;
|
||||
origin === 'keyup' && othis[(isCreatable ? (not && !isCreateOption) : not) ? 'addClass' : 'removeClass'](HIDE);
|
||||
});
|
||||
|
@ -647,23 +647,23 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var none = num === dds.length;
|
||||
return callback(none, hasEquals), none;
|
||||
};
|
||||
|
||||
|
||||
// 搜索匹配
|
||||
var search = function(e){
|
||||
var value = this.value, keyCode = e.keyCode;
|
||||
|
||||
if(keyCode === 9 || keyCode === 13
|
||||
|| keyCode === 37 || keyCode === 38
|
||||
|
||||
if(keyCode === 9 || keyCode === 13
|
||||
|| keyCode === 37 || keyCode === 38
|
||||
|| keyCode === 39 || keyCode === 40
|
||||
){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if(needPlaceholderPatch && e.target.__ieph){
|
||||
e.target.__ieph = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
notOption(value, function(none, hasEquals){
|
||||
if(isCreatable){
|
||||
if(hasEquals){
|
||||
|
@ -671,10 +671,10 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
}else{
|
||||
var createOptionElem = dl.children('.' + CREATE_OPTION);
|
||||
if(createOptionElem[0]){
|
||||
createOptionElem.attr('lay-value', value).html(util.escape(value));
|
||||
createOptionElem.attr('lay-value', value).text(value);
|
||||
}else{
|
||||
// 临时显示在顶部
|
||||
var ddElem = $('<dd>').addClass(CREATE_OPTION).attr('lay-value', value).html(util.escape(value));
|
||||
var ddElem = $('<dd>').addClass(CREATE_OPTION).attr('lay-value', value).text(value);
|
||||
var firstOptionELem = dl.children().eq(0);
|
||||
var hasTips = firstOptionELem.hasClass('layui-select-tips');
|
||||
firstOptionELem[hasTips ? 'after' : 'before'](ddElem);
|
||||
|
@ -688,7 +688,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
}
|
||||
}
|
||||
}, 'keyup');
|
||||
|
||||
|
||||
// 当搜索值清空时
|
||||
if(value === ''){
|
||||
// 取消选中项
|
||||
|
@ -698,21 +698,21 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
dl.find('.'+ NONE).remove();
|
||||
isCreatable && dl.children('.' + CREATE_OPTION).remove();
|
||||
}
|
||||
|
||||
|
||||
followScroll(); // 定位滚动条
|
||||
};
|
||||
|
||||
|
||||
if(isSearch){
|
||||
input.on('input propertychange', layui.debounce(search, 50)).on('blur', function(e){
|
||||
var selectedIndex = select[0].selectedIndex;
|
||||
|
||||
|
||||
initValue = $(select[0].options[selectedIndex]).text(); // 重新获得初始选中值
|
||||
|
||||
|
||||
// 如果是第一项,且文本值等于 placeholder,则清空初始值
|
||||
if(selectedIndex === 0 && initValue === input.attr('placeholder')){
|
||||
initValue = '';
|
||||
}
|
||||
|
||||
|
||||
setTimeout(function(){
|
||||
notOption(input.val(), function(none){
|
||||
initValue || input.val(''); // none && !initValue
|
||||
|
@ -725,9 +725,9 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
dl.on('click', 'dd', function(){
|
||||
var othis = $(this), value = othis.attr('lay-value');
|
||||
var filter = select.attr('lay-filter'); // 获取过滤器
|
||||
|
||||
|
||||
if(othis.hasClass(DISABLED)) return false;
|
||||
|
||||
|
||||
if(othis.hasClass('layui-select-tips')){
|
||||
input.val('');
|
||||
} else {
|
||||
|
@ -759,7 +759,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
dl.on('mousedown pointerdown touchstart', function(e){
|
||||
layui.stope(e);
|
||||
})
|
||||
|
||||
|
||||
reElem.find('dl>dt').on('click', function(e){
|
||||
return false;
|
||||
});
|
||||
|
@ -777,81 +777,128 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
handleObj.handler();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 初始渲染 select 组件选项
|
||||
selects.each(function(index, select){
|
||||
selects.each(function(index, select) {
|
||||
var othis = $(this);
|
||||
var hasRender = othis.next('.'+CLASS);
|
||||
var disabled = this.disabled;
|
||||
var value = select.value;
|
||||
var selected = $(select.options[select.selectedIndex]); // 获取当前选中项
|
||||
var optionsFirst = select.options[0];
|
||||
|
||||
if(typeof othis.attr('lay-ignore') === 'string') return othis.show();
|
||||
|
||||
var isSearch = typeof othis.attr('lay-search') === 'string'
|
||||
var isCreatable = typeof othis.attr('lay-creatable') === 'string' && isSearch
|
||||
var isAppendTo = typeof othis.attr('lay-append-to') === 'string'
|
||||
|
||||
// 为忽略渲染的 select 元素保持原生显示状态
|
||||
if (othis.closest('[lay-ignore]').length) {
|
||||
return othis.show();
|
||||
}
|
||||
|
||||
var isSearch = typeof othis.attr('lay-search') === 'string';
|
||||
var isCreatable = typeof othis.attr('lay-creatable') === 'string' && isSearch;
|
||||
var isAppendTo = typeof othis.attr('lay-append-to') === 'string';
|
||||
var placeholder = optionsFirst
|
||||
? (optionsFirst.value ? TIPS : (optionsFirst.innerHTML || TIPS))
|
||||
? (optionsFirst.value ? TIPS : (optionsFirst.innerText || TIPS))
|
||||
: TIPS;
|
||||
|
||||
// 替代元素
|
||||
var reElem = $(['<div class="'+ (isSearch ? '' : 'layui-unselect ') + CLASS
|
||||
,(disabled ? ' layui-select-disabled' : '') + '"></div>'].join(''));
|
||||
// 用于替代 select 的外层容器
|
||||
var selectWrapper = (function() {
|
||||
var elem = $('<div class="'+ CLASS +'"></div>');
|
||||
if (!isSearch) {
|
||||
elem.addClass('layui-unselect');
|
||||
}
|
||||
if (disabled) {
|
||||
elem.addClass('layui-select-disabled');
|
||||
}
|
||||
return elem;
|
||||
})();
|
||||
|
||||
var triggerElem = $([
|
||||
'<div class="'+ TITLE +'">'
|
||||
,('<input type="text" placeholder="'+ util.escape($.trim(placeholder)) +'" '
|
||||
+('value="'+ util.escape($.trim(value ? selected.html() : '')) +'"') // 默认值
|
||||
+((!disabled && isSearch) ? '' : ' readonly') // 是否开启搜索
|
||||
+' class="layui-input'
|
||||
+(isSearch ? '' : ' layui-unselect')
|
||||
+ (disabled ? (' ' + DISABLED) : '') +'">') // 禁用状态
|
||||
,'<i class="layui-edge"></i>'
|
||||
,'</div>'].join(''));
|
||||
var inputElem = (function() {
|
||||
var elem = $('<input type="text" class="layui-input">');
|
||||
|
||||
var contentElem = $(['<dl class="layui-anim layui-anim-upbit'+ (othis.find('optgroup')[0] ? ' layui-select-group' : '') +'">'
|
||||
,function(options){
|
||||
// 设置占位符和默认值
|
||||
elem.prop('placeholder', $.trim(placeholder));
|
||||
elem.val($.trim(value ? selected.text() : ''));
|
||||
|
||||
// 设置未开启搜索或禁用时的输入框只读状态
|
||||
if (!isSearch || disabled) {
|
||||
elem.prop('readonly', true);
|
||||
}
|
||||
|
||||
// 添加禁用状态时的 className
|
||||
if (disabled) {
|
||||
elem.addClass(DISABLED);
|
||||
}
|
||||
|
||||
return elem;
|
||||
})();
|
||||
|
||||
var titleElem = (function() {
|
||||
var elem = $('<div class="'+ TITLE +'"></div>');
|
||||
elem.append(inputElem);
|
||||
elem.append('<i class="layui-edge"></i>');
|
||||
return elem;
|
||||
})();
|
||||
|
||||
var contentElem = (function() {
|
||||
var elem = $('<dl class="layui-anim layui-anim-upbit"></dl>');
|
||||
if (othis.find('optgroup')[0]) {
|
||||
elem.addClass('layui-select-group');
|
||||
}
|
||||
var content = function() {
|
||||
var arr = [];
|
||||
layui.each(options, function(index, item){
|
||||
layui.each(othis.find('optgroup,option'), function(index, item) {
|
||||
var tagName = item.tagName.toLowerCase();
|
||||
|
||||
if(index === 0 && !item.value && tagName !== 'optgroup'){
|
||||
arr.push('<dd lay-value="" class="layui-select-tips">'+ $.trim(item.innerHTML || TIPS) +'</dd>');
|
||||
} else if(tagName === 'optgroup'){
|
||||
arr.push('<dt>'+ item.label +'</dt>');
|
||||
var dd = $('<dd lay-value=""></dd>');
|
||||
if (index === 0 && !item.value && tagName !== 'optgroup') {
|
||||
dd.addClass('layui-select-tips');
|
||||
dd.text($.trim(item.innerText || TIPS));
|
||||
arr.push(dd.prop('outerHTML'));
|
||||
} else if(tagName === 'optgroup') {
|
||||
var dt = $('<dt></dt>');
|
||||
dt.text(item.label);
|
||||
arr.push(dt.prop('outerHTML'));
|
||||
} else {
|
||||
arr.push('<dd lay-value="'+ util.escape(item.value) +'" class="'+ (value === item.value ? THIS : '') + (item.disabled ? (' '+DISABLED) : '') +'">'+ $.trim(item.innerHTML) +'</dd>');
|
||||
dd.attr('lay-value', item.value);
|
||||
if (value === item.value) {
|
||||
dd.addClass(THIS);
|
||||
}
|
||||
if (item.disabled) {
|
||||
dd.addClass(DISABLED);
|
||||
}
|
||||
dd.text($.trim(item.innerText));
|
||||
arr.push(dd.prop('outerHTML'));
|
||||
}
|
||||
});
|
||||
arr.length === 0 && arr.push('<dd lay-value="" class="'+ DISABLED +'">没有选项</dd>');
|
||||
if (arr.length === 0) {
|
||||
arr.push('<dd lay-value="" class="'+ DISABLED +'">None</dd>');
|
||||
}
|
||||
return arr.join('');
|
||||
}(othis.find('*')) +'</dl>'
|
||||
].join(''));
|
||||
|
||||
// 如果已经渲染,则Rerender
|
||||
if(hasRender[0]){
|
||||
if(isAppendTo){
|
||||
}();
|
||||
elem.html(content);
|
||||
return elem;
|
||||
})();
|
||||
|
||||
// 如果已经渲染,则 Rerender
|
||||
if (hasRender[0]) {
|
||||
if (isAppendTo) {
|
||||
var panelWrapElem = hasRender.data(PANEL_ELEM_DATA);
|
||||
panelWrapElem && panelWrapElem.remove();
|
||||
}
|
||||
hasRender.remove();
|
||||
}
|
||||
if(isAppendTo){
|
||||
reElem.append(triggerElem);
|
||||
othis.after(reElem);
|
||||
if (isAppendTo) {
|
||||
selectWrapper.append(titleElem);
|
||||
othis.after(selectWrapper);
|
||||
var contentWrapElem = $('<div class="'+ CLASS + ' ' + PANEL_WRAP +'"></div>').append(contentElem);
|
||||
reElem.data(PANEL_ELEM_DATA, contentWrapElem); // 将面板元素对象记录在触发元素 data 中,重新渲染时需要清理旧面板元素
|
||||
events.call(this, contentWrapElem, triggerElem, disabled, isSearch, isCreatable, isAppendTo);
|
||||
}else{
|
||||
reElem.append(triggerElem).append(contentElem);
|
||||
othis.after(reElem);
|
||||
events.call(this, reElem, triggerElem, disabled, isSearch, isCreatable, isAppendTo);
|
||||
selectWrapper.data(PANEL_ELEM_DATA, contentWrapElem); // 将面板元素对象记录在触发元素 data 中,重新渲染时需要清理旧面板元素
|
||||
events.call(this, contentWrapElem, titleElem, disabled, isSearch, isCreatable, isAppendTo);
|
||||
} else {
|
||||
selectWrapper.append(titleElem).append(contentElem);
|
||||
othis.after(selectWrapper);
|
||||
events.call(this, selectWrapper, titleElem, disabled, isSearch, isCreatable, isAppendTo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 复选框/开关
|
||||
,checkbox: function(elem){
|
||||
var CLASS = {
|
||||
|
@ -872,14 +919,14 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var skin = check.attr('lay-skin') || 'primary';
|
||||
var isSwitch = skin === 'switch';
|
||||
var isPrimary = skin === 'primary';
|
||||
|
||||
|
||||
// 勾选
|
||||
reElem.on('click', function(){
|
||||
var filter = check.attr('lay-filter') // 获取过滤器
|
||||
|
||||
// 禁用
|
||||
if(check[0].disabled) return;
|
||||
|
||||
|
||||
// 半选
|
||||
if (check[0].indeterminate) {
|
||||
check[0].indeterminate = false;
|
||||
|
@ -887,7 +934,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
|
||||
// 开关
|
||||
check[0].checked = !check[0].checked
|
||||
|
||||
|
||||
// 事件
|
||||
layui.event.call(check[0], MOD_NAME, RE_CLASS[2]+'('+ filter +')', {
|
||||
elem: check[0],
|
||||
|
@ -898,7 +945,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
|
||||
that.syncAppearanceOnPropChanged(this, 'checked', function(){
|
||||
if(isSwitch){
|
||||
var title = (reElem.next('*[lay-checkbox]')[0]
|
||||
var title = (reElem.next('*[lay-checkbox]')[0]
|
||||
? reElem.next().html()
|
||||
: check.attr('title') || ''
|
||||
).split('|');
|
||||
|
@ -917,7 +964,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
})
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 遍历复选框
|
||||
checks.each(function(index, check){
|
||||
var othis = $(this);
|
||||
|
@ -933,7 +980,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
// 替代元素
|
||||
var hasRender = othis.next('.' + RE_CLASS[0]);
|
||||
hasRender[0] && hasRender.remove(); // 若已经渲染,则 Rerender
|
||||
|
||||
|
||||
// 若存在标题模板,则优先读取标题模板
|
||||
var titleTplAttrs = [];
|
||||
if(othis.next('[lay-checkbox]')[0]){
|
||||
|
@ -951,7 +998,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
|
||||
// 若为开关,则对 title 进行分隔解析
|
||||
title = skin === 'switch' ? title.split('|') : [title];
|
||||
|
||||
|
||||
if(typeof othis.attr('lay-ignore') === 'string') return othis.show();
|
||||
|
||||
// 处理 IE8 indeterminate 属性重新定义 get set 后无法设置值的问题
|
||||
|
@ -985,7 +1032,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
events.call(this, reElem, RE_CLASS);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 单选框
|
||||
,radio: function(elem){
|
||||
var CLASS = 'layui-form-radio';
|
||||
|
@ -996,14 +1043,14 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var events = function(reElem){
|
||||
var radio = $(this);
|
||||
var ANIM = 'layui-anim-scaleSpring';
|
||||
|
||||
|
||||
reElem.on('click', function(){
|
||||
var filter = radio.attr('lay-filter'); // 获取过滤器
|
||||
|
||||
|
||||
if(radio[0].disabled) return;
|
||||
|
||||
|
||||
radio[0].checked = true;
|
||||
|
||||
|
||||
layui.event.call(radio[0], MOD_NAME, 'radio('+ filter +')', {
|
||||
elem: radio[0],
|
||||
value: radio[0].value,
|
||||
|
@ -1028,13 +1075,13 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
// 初始渲染
|
||||
radios.each(function(index, radio){
|
||||
var othis = $(this), hasRender = othis.next('.' + CLASS);
|
||||
var disabled = this.disabled;
|
||||
var skin = othis.attr('lay-skin');
|
||||
|
||||
|
||||
if(typeof othis.attr('lay-ignore') === 'string') return othis.show();
|
||||
|
||||
if(needCheckboxFallback){
|
||||
|
@ -1057,9 +1104,9 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
}
|
||||
}
|
||||
titleTplAttrs = titleTplAttrs.join(' ');
|
||||
|
||||
|
||||
// 替代元素
|
||||
var reElem = $(['<div class="layui-unselect '+ CLASS,
|
||||
var reElem = $(['<div class="layui-unselect '+ CLASS,
|
||||
(radio.checked ? (' '+ CLASS +'ed') : ''), // 选中状态
|
||||
(disabled ? ' layui-radio-disabled '+DISABLED : '') +'"', // 禁用状态
|
||||
(skin ? ' lay-skin="'+ skin +'"' : ''),
|
||||
|
@ -1112,7 +1159,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
}
|
||||
return that;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* checkbox 和 radio 指定属性变化时自动更新 UI
|
||||
* 只能用于 boolean 属性
|
||||
|
@ -1139,12 +1186,12 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
handler.call(this);
|
||||
}
|
||||
})
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
return function(elem, propName, handler){
|
||||
var originProps = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, propName);
|
||||
|
||||
|
||||
Object.defineProperty(elem, propName,
|
||||
lay.extend({}, originProps, {
|
||||
// 此处的 get 是为了兼容 IE<9
|
||||
|
@ -1195,31 +1242,31 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
value = typeof value === 'string' ? $.trim(value) : value;
|
||||
|
||||
othis.removeClass(DANGER); // 移除警示样式
|
||||
|
||||
|
||||
// 遍历元素绑定的验证规则
|
||||
layui.each(vers, function(_, thisVer) {
|
||||
var verst; // 校验结果
|
||||
var errorText = ''; // 错误提示文本
|
||||
var rule = verify[thisVer]; // 获取校验规则
|
||||
|
||||
|
||||
// 匹配验证规则
|
||||
if (rule) {
|
||||
verst = typeof rule === 'function'
|
||||
? errorText = rule(value, item)
|
||||
? errorText = rule(value, item)
|
||||
: !rule[0].test(value); // 兼容早期数组中的正则写法
|
||||
|
||||
|
||||
// 是否属于美化替换后的表单元素
|
||||
var isForm2Elem = item.tagName.toLowerCase() === 'select' || (
|
||||
/^(checkbox|radio)$/.test(item.type)
|
||||
);
|
||||
|
||||
|
||||
errorText = errorText || rule[1];
|
||||
|
||||
|
||||
// 获取自定义必填项提示文本
|
||||
if (thisVer === 'required') {
|
||||
errorText = othis.attr('lay-reqtext') || errorText;
|
||||
}
|
||||
|
||||
|
||||
// 若命中校验规则
|
||||
if (verst) {
|
||||
// 提示层风格
|
||||
|
@ -1234,7 +1281,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
}(), {tips: 1});
|
||||
} else if(verType === 'alert') {
|
||||
layer.alert(errorText, {title: '提示', shadeClose: true});
|
||||
}
|
||||
}
|
||||
// 若返回的为字符或数字,则自动弹出默认提示框;否则由 verify 方法中处理提示
|
||||
else if(/\b(string|number)\b/.test(typeof errorText)) {
|
||||
layer.msg(errorText, {icon: 5, shift: 6});
|
||||
|
@ -1243,7 +1290,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
setTimeout(function() {
|
||||
(isForm2Elem ? othis.next().find('input') : item).focus();
|
||||
}, 7);
|
||||
|
||||
|
||||
othis.addClass(DANGER);
|
||||
return intercept = true;
|
||||
}
|
||||
|
@ -1262,13 +1309,13 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var button = $(this); // 当前触发的按钮
|
||||
|
||||
// 表单域 lay-filter 属性值
|
||||
var layFilter = typeof filter === 'string'
|
||||
? filter
|
||||
var layFilter = typeof filter === 'string'
|
||||
? filter
|
||||
: button.attr('lay-filter');
|
||||
|
||||
// 当前所在表单域
|
||||
var elem = this.getFormElem
|
||||
? this.getFormElem(layFilter)
|
||||
var elem = this.getFormElem
|
||||
? this.getFormElem(layFilter)
|
||||
: button.parents(ELEM).eq(0);
|
||||
|
||||
// 获取需要校验的元素
|
||||
|
@ -1286,10 +1333,10 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
,form: this.getFormElem ? elem[0] : button.parents('form')[0] // 当前所在的 form 元素,如果存在的话
|
||||
,field: field // 当前表单数据
|
||||
};
|
||||
|
||||
|
||||
// 回调
|
||||
typeof callback === 'function' && callback(params);
|
||||
|
||||
|
||||
// 事件
|
||||
return layui.event.call(this, MOD_NAME, 'submit('+ layFilter +')', params);
|
||||
};
|
||||
|
@ -1344,16 +1391,16 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var form = new Form();
|
||||
var $dom = $(document);
|
||||
var $win = $(window);
|
||||
|
||||
|
||||
// 初始自动完成渲染
|
||||
$(function(){
|
||||
form.render();
|
||||
});
|
||||
|
||||
|
||||
// 表单 reset 重置渲染
|
||||
$dom.on('reset', ELEM, function(){
|
||||
var filter = $(this).attr('lay-filter');
|
||||
|
@ -1361,12 +1408,10 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
form.render(null, filter);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
|
||||
// 表单提交事件
|
||||
$dom.on('submit', ELEM, submit)
|
||||
.on('click', '*[lay-submit]', submit);
|
||||
|
||||
|
||||
exports(MOD_NAME, form);
|
||||
});
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue