mirror of https://github.com/layui/layui
Merge branch 'main' into 2.10-dev
commit
c112285cb3
|
@ -1,6 +1,10 @@
|
|||
name: 😄 创建议题
|
||||
description: 此处只受理 Bug 报告、功能请求。若是其他业务相关的问题建议在 Discussions 寻求社区帮助。
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> 💡 请遵循标题格式:**[组件名称] 描述问题的标题** ( 例如:[table] 表格能否支持自定义请求 )
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 议题条件
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -12,7 +12,7 @@ toc: true
|
|||
| className | 描述 |
|
||||
| --- | --- |
|
||||
| layui-main | 设置一个固定宽度为 `1160px` 的水平居中块 |
|
||||
| layui-border-box | 设置元素及其所有子元素均为 `box-sizing: content-box` 模型的容器 |
|
||||
| layui-border-box | 设置元素及其所有子元素均为 `box-sizing: border-box` 模型的容器 |
|
||||
| layui-clear | 清除前面的同级元素产生的浮动 |
|
||||
| layui-clear-space <sup>2.8+</sup> | 清除容器内的空白符 |
|
||||
| layui-inline | 设置元素为内联块状结构 |
|
||||
|
|
|
@ -114,7 +114,8 @@ toc: true
|
|||
数字输入框 <sup>2.8.9+</sup>
|
||||
</h3>
|
||||
|
||||
一般搭配 `<input type="number">` 使用,用于替代原生数字输入框,支持的属性如下:
|
||||
一般搭配 `<input type="text">` 使用,用于替代原生数字输入框,支持的属性如下:
|
||||
注:<sup>2.10+</sup> 之前的版本,使用 `type="number"` 类型的输入框。
|
||||
|
||||
| 属性 | 描述 |
|
||||
| --- | --- |
|
||||
|
@ -122,6 +123,8 @@ toc: true
|
|||
| min | 设置数字的最小值 |
|
||||
| max | 设置数字的最大值 |
|
||||
| lay-precision <sup>2.8.18+</sup> | 设置数字的小数位精度。注<sup>2.9.8+</sup>:若值为 `0`,则表示取整。 |
|
||||
| lay-step-strictly <sup>2.10+</sup> | 步长严格模式,只能输入步长的倍数 |
|
||||
| lay-wheel <sup>2.10+</sup> | 是否启用滚轮或触摸板事件处理 |
|
||||
|
||||
### 示例
|
||||
|
||||
|
@ -134,19 +137,22 @@ toc: true
|
|||
<hr class="ws-space-16">
|
||||
<div class="layui-row layui-col-space16">
|
||||
<div class="layui-col-xs6">
|
||||
<input type="number" lay-affix="number" placeholder="设置 step 为 0.01" step="0.01" class="layui-input">
|
||||
<input type="text" lay-affix="number" placeholder="设置 step 为 0.01" step="0.01" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs6">
|
||||
<input type="number" lay-affix="number" placeholder="设置 step,min,max" step="10" min="0" max="100" class="layui-input">
|
||||
<input type="text" lay-affix="number" placeholder="设置 step,min,max" step="10" min="0" max="100" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs6">
|
||||
<input type="text" lay-affix="number" placeholder="步长严格模式" lay-step-strictly step="10" min="0" max="100" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<input type="number" lay-affix="number" placeholder="设置小数位精度为 2" step="0.1" lay-precision="2" class="layui-input">
|
||||
<input type="text" lay-affix="number" placeholder="设置小数位精度为 2" step="0.1" lay-precision="2" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<input type="number" lay-affix="number" readonly placeholder="不允许输入状态" class="layui-input">
|
||||
<input type="text" lay-affix="number" readonly placeholder="不允许输入状态" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<input type="number" lay-affix="number" disabled placeholder="禁用状态" class="layui-input">
|
||||
<input type="text" lay-affix="number" disabled placeholder="禁用状态" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,10 +9,27 @@ toc: true
|
|||
|
||||
<h2 id="2.9.x" lay-toc="{title: '2.9.x'}"></h2>
|
||||
|
||||
<h2 id="v2.9.24" class="ws-anchor">
|
||||
v2.9.24
|
||||
<span class="layui-badge-rim">2025-03-07</span>
|
||||
<span class="layui-badge-rim" style="color: #16b777;">稳定版</span>
|
||||
</h2>
|
||||
|
||||
- #### layer
|
||||
- 改进 打开弹层后设置页面滚动条逻辑 #2537 @Sight-wcg
|
||||
- #### treeTable
|
||||
- 修复 treeToFlat 改变根节点 pid 问题 #2526 @Sight-wcg
|
||||
- 修复 checkbox 重复更新的问题,大约可提升 30% 性能 #2528 @Sight-wcg
|
||||
- #### code
|
||||
- 修复 选项卡底边框显示异常问题 #2519 @Sight-wcg
|
||||
|
||||
### 下载: [layui-v2.9.24.zip](https://gitee.com/layui/layui/attach_files/2085224/download)
|
||||
|
||||
---
|
||||
|
||||
<h2 id="v2.9.23" class="ws-anchor">
|
||||
v2.9.23
|
||||
<span class="layui-badge-rim">2025-02-19</span>
|
||||
<span class="layui-badge-rim" style="color: #16b777;">稳定版</span>
|
||||
</h2>
|
||||
|
||||
- #### 基础
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "layui",
|
||||
"version": "2.9.23",
|
||||
"version": "2.9.24",
|
||||
"description": "Classic modular Front-End UI library",
|
||||
"keywords": [
|
||||
"layui",
|
||||
|
|
|
@ -841,7 +841,8 @@ hr.layui-border-black{border-width: 0 0 1px;}
|
|||
.layui-input-wrap .layui-input[type="number"]::-webkit-outer-spin-button,
|
||||
.layui-input-wrap .layui-input[type="number"]::-webkit-inner-spin-button{-webkit-appearance: none !important;}
|
||||
.layui-input-wrap .layui-input[type="number"]{-moz-appearance: textfield; -webkit-appearance: textfield; appearance: textfield;}
|
||||
.layui-input-wrap .layui-input[type="number"].layui-input-number-out-of-range{color:#ff5722;}
|
||||
.layui-input-wrap .layui-input.layui-input-number-out-of-range,
|
||||
.layui-input-wrap .layui-input.layui-input-number-invalid{color:#ff5722;}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -48,8 +48,7 @@ html #layuicss-skincodecss{display: none; position: absolute; width: 1989px;}
|
|||
.layui-code-preview > .layui-code,
|
||||
.layui-code-preview > .layui-code-view{margin: 0;}
|
||||
.layui-code-preview > .layui-tab{position: relative; z-index: 1; margin-bottom: 0;}
|
||||
.layui-code-preview > .layui-tab > .layui-tab-title{border-width: 0;}
|
||||
.layui-code-preview .layui-code-item{display: none;}
|
||||
.layui-code-preview .layui-code-item{display: none; border-top-width: 0;}
|
||||
.layui-code-preview .layui-code-view > .layui-code-lines > .layui-code-line{}
|
||||
.layui-code-item-preview{position: relative; padding: 16px;}
|
||||
.layui-code-item-preview > iframe{position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;}
|
||||
|
@ -62,7 +61,7 @@ html #layuicss-skincodecss{display: none; position: absolute; width: 1989px;}
|
|||
|
||||
/* 全屏风格 */
|
||||
.layui-code-full{position: fixed; left: 0; top: 0; z-index: 1111111; width: 100%; height: 100%; background-color: #fff;}
|
||||
.layui-code-full .layui-code-item{width: 100% !important; border-width: 0 !important; border-top-width: 1px !important;}
|
||||
.layui-code-full .layui-code-item{width: 100% !important; border-width: 0 !important;}
|
||||
.layui-code-full .layui-code-item,
|
||||
.layui-code-full .layui-code-view,
|
||||
.layui-code-full .layui-code-wrap{height: calc(100vh - 51px) !important; box-sizing: border-box;}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
};
|
||||
|
||||
var Layui = function(){
|
||||
this.v = '2.9.23'; // Layui 版本号
|
||||
this.v = '2.9.24'; // Layui 版本号
|
||||
};
|
||||
|
||||
// 识别预先可能定义的指定全局对象
|
||||
|
|
|
@ -19,6 +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 BAD_INPUT = 'layui-input-number-invalid';
|
||||
|
||||
var Form = function(){
|
||||
this.config = {
|
||||
|
@ -194,10 +195,15 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
var precision = Number(elem.attr('lay-precision'));
|
||||
var noAction = eventType !== 'click' && rawValue === ''; // 初始渲染和失焦时空值不作处理
|
||||
var isInit = eventType === 'init';
|
||||
var isBadInput = isNaN(value);
|
||||
var isStepStrictly = typeof elem.attr('lay-step-strictly') === 'string';
|
||||
|
||||
if(isNaN(value)) return; // 若非数字,则不作处理
|
||||
elem.toggleClass(BAD_INPUT, isBadInput);
|
||||
if(isBadInput) return; // 若非数字,则不作处理
|
||||
|
||||
if(eventType === 'click'){
|
||||
// 兼容旧版行为,2.10 以前 readonly 不禁用控制按钮
|
||||
if(elem[0].type === 'text' && typeof elem.attr('readonly') === 'string') return;
|
||||
var isDecrement = !!$(that).index() // 0: icon-up, 1: icon-down
|
||||
value = isDecrement ? value - step : value + step;
|
||||
}
|
||||
|
@ -214,6 +220,9 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
if (!noAction) {
|
||||
// 初始渲染时只处理数字精度
|
||||
if (!isInit) {
|
||||
if(isStepStrictly){
|
||||
value = Math.round(value / step) * step;
|
||||
}
|
||||
if(value <= min) value = min;
|
||||
if(value >= max) value = max;
|
||||
}
|
||||
|
@ -223,7 +232,9 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
} else if(precision > 0) { // 小数位精度
|
||||
value = value.toFixed(precision);
|
||||
}
|
||||
|
||||
elem.val(value);
|
||||
elem.attr('lay-input-mirror', elem.val())
|
||||
}
|
||||
|
||||
// 超出范围的样式
|
||||
|
@ -369,6 +380,71 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
className: 'layui-input-number',
|
||||
disabled: othis.is('[disabled]'), // 跟随输入框禁用状态
|
||||
init: function(elem){
|
||||
// 旧版浏览器不支持更改 input 元素的 type 属性,需要主动设置 text
|
||||
if(elem.attr('type') === 'text' || elem[0].type === 'text'){
|
||||
var ns = '.lay_input_number';
|
||||
var skipCheck = false;
|
||||
var isComposition = false;
|
||||
var isReadonly = typeof elem.attr('readonly') === 'string';
|
||||
var isMouseWheel = typeof elem.attr('lay-wheel') === 'string';
|
||||
var btnElem = elem.next('.layui-input-number').children('i');
|
||||
// 旧版浏览器不支持 beforeInput 事件,需要设置一个 attr 存储输入前的值
|
||||
elem.attr('lay-input-mirror', elem.val());
|
||||
elem.off(ns);
|
||||
// 旧版浏览器不支持 event.inputType 属性,需要用 keydown 事件来判断是否跳过输入检查
|
||||
elem.on('keydown' + ns, function (e) {
|
||||
skipCheck = false;
|
||||
if (e.keyCode === 8 || e.keyCode === 46) { // Backspace || Delete
|
||||
skipCheck = true;
|
||||
}
|
||||
// Up & Down 键盘事件处理
|
||||
if(!isReadonly && btnElem.length === 2 && (e.keyCode === 38 || e.keyCode === 40)){
|
||||
e.preventDefault();
|
||||
btnElem.eq(e.keyCode === 38 ? 0 : 1).click();
|
||||
}
|
||||
})
|
||||
elem.on('input' + ns + ' propertychange' + ns, function (e) {
|
||||
if (isComposition || (e.type === 'propertychange' && e.originalEvent.propertyName !== 'value')) return;
|
||||
if (skipCheck || canInputNumber(this.value)) {
|
||||
elem.attr('lay-input-mirror', this.value);
|
||||
} else {
|
||||
// 恢复输入前的值
|
||||
this.value = elem.attr('lay-input-mirror');
|
||||
}
|
||||
elem.toggleClass(BAD_INPUT, isNaN(Number(this.value)));
|
||||
});
|
||||
elem.on('compositionstart' + ns, function () {
|
||||
isComposition = true;
|
||||
});
|
||||
elem.on('compositionend' + ns, function () {
|
||||
isComposition = false;
|
||||
elem.trigger('input');
|
||||
})
|
||||
// 响应鼠标滚轮或触摸板
|
||||
if(isMouseWheel){
|
||||
elem.on(['wheel','mousewheel','DOMMouseScroll'].join(ns + ' ') + ns, function (e) {
|
||||
if(!btnElem.length) return;
|
||||
if(!$(this).is(':focus')) return;
|
||||
var direction = 0;
|
||||
e.preventDefault();
|
||||
// IE9+,chrome 和 firefox 同时添加 'wheel' 和 'mousewheel' 事件时,只执行 'wheel' 事件
|
||||
if(e.type === 'wheel'){
|
||||
e.deltaX = e.originalEvent.deltaX;
|
||||
e.deltaY = e.originalEvent.deltaY;
|
||||
direction = Math.abs(e.deltaX) >= Math.abs(e.deltaY) ? e.deltaX : e.deltaY;
|
||||
}else if(e.type === 'mousewheel' ){
|
||||
direction = -e.originalEvent.wheelDelta;
|
||||
}else if(e.type === 'DOMMouseScroll'){
|
||||
direction = e.originalEvent.detail;
|
||||
}
|
||||
btnElem.eq(direction > 0 ? 1 : 0).click();
|
||||
})
|
||||
}
|
||||
|
||||
if(isReadonly){
|
||||
btnElem.addClass(DISABLED);
|
||||
}
|
||||
}
|
||||
handleInputNumber.call(this, elem, 'init')
|
||||
},
|
||||
click: function(elem){
|
||||
|
@ -1344,6 +1420,31 @@ layui.define(['lay', 'layer', 'util'], function(exports){
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 修改自 https://github.com/Tencent/tdesign-common/blob/53786c58752401e648cc45918f2a4dbb9e8cecfa/js/input-number/number.ts#L209
|
||||
var specialCode = ['-', '.', 'e', 'E', '+'];
|
||||
function canInputNumber(number) {
|
||||
if (number === '') return true;
|
||||
// 数字最前方不允许出现连续的两个 0
|
||||
if (number.slice(0, 2) === '00') return false;
|
||||
// 不能出现空格
|
||||
if (number.match(/\s/g)) return false;
|
||||
// 只能出现一个点(.)
|
||||
var tempMatched = number.match(/\./g);
|
||||
if (tempMatched && tempMatched.length > 1) return false;
|
||||
// 只能出现一个e(e)
|
||||
tempMatched = number.match(/e/g);
|
||||
if (tempMatched && tempMatched.length > 1) return false;
|
||||
// 只能出现一个负号(-)或 一个正号(+),并且在第一个位置;但允许 3e+10 这种形式
|
||||
var tempNumber = number.slice(1);
|
||||
tempMatched = tempNumber.match(/(\+|-)/g);
|
||||
if (tempMatched && (!/e(\+|-)/i.test(tempNumber) || tempMatched.length > 1)) return false;
|
||||
// 允许输入数字字符
|
||||
var isNumber = !isNaN(Number(number));
|
||||
if (!isNumber && !(specialCode.indexOf(number.slice(-1)) !== -1)) return false;
|
||||
if (/e/i.test(number) && (!/\de/i.test(number) || /e\./.test(number))) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
var form = new Form();
|
||||
var $dom = $(document);
|
||||
|
|
|
@ -1021,16 +1021,20 @@ ready.record = function(layero){
|
|||
|
||||
// 设置页面滚动条
|
||||
ready.setScrollbar = function(index){
|
||||
doms.html.css('overflow', 'hidden').attr('layer-full', index);
|
||||
doms.html.css('overflow', 'hidden');
|
||||
};
|
||||
|
||||
// 恢复页面滚动条
|
||||
ready.restScrollbar = function(index){
|
||||
if(doms.html.attr('layer-full') == index){
|
||||
doms.html[0].style[doms.html[0].style.removeProperty
|
||||
? 'removeProperty'
|
||||
: 'removeAttribute']('overflow');
|
||||
doms.html.removeAttr('layer-full');
|
||||
ready.restScrollbar = function(index) {
|
||||
// 关闭和大小化, layer-full 处理
|
||||
var targetEl = $('.'+ doms[0]).filter(function(){
|
||||
var layero = $(this);
|
||||
return layero.data('config').scrollbar === false
|
||||
&& layero.data('maxminStatus') !== 'min'
|
||||
&& layero.attr('times') !== String(index);
|
||||
});
|
||||
if(targetEl.length === 0){
|
||||
doms.html.css('overflow', '');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1230,9 +1234,7 @@ layer.full = function(index){
|
|||
layero.data('maxminStatus', 'max');
|
||||
ready.record(layero); // 记录当前尺寸、坐标
|
||||
|
||||
if(!doms.html.attr('layer-full')){
|
||||
ready.setScrollbar(index);
|
||||
}
|
||||
ready.setScrollbar(index);
|
||||
|
||||
setTimeout(function(){
|
||||
var isfix = layero.css('position') === 'fixed';
|
||||
|
|
|
@ -1746,6 +1746,9 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
|
|||
var isCheckMult = layui.type(opts.index) === 'array'; // 是否操作多个
|
||||
var isCheckAllOrMult = isCheckAll || isCheckMult; // 是否全选或多选
|
||||
|
||||
// treeTable 内部已处理选中,此处不再处理
|
||||
if(options.tree && options.tree.view) return;
|
||||
|
||||
// 全选或多选时
|
||||
if (isCheckAllOrMult) {
|
||||
that.layBox.addClass(DISABLED_TRANSITION); // 减少回流
|
||||
|
@ -1839,7 +1842,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
|
|||
if(isCheckAllOrMult){
|
||||
setTimeout(function(){
|
||||
that.layBox.removeClass(DISABLED_TRANSITION);
|
||||
},100)
|
||||
}, 100)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -387,7 +387,8 @@ layui.define(['table'], function (exports) {
|
|||
layui.each(tableData, function (i1, item1) {
|
||||
var dataIndex = (parentIndex ? parentIndex + '-' : '') + i1;
|
||||
var dataNew = $.extend({}, item1);
|
||||
dataNew[pIdKey] = item1[pIdKey] || parentId;
|
||||
|
||||
dataNew[pIdKey] = typeof item1[pIdKey] !== 'undefined' ? item1[pIdKey] : parentId;
|
||||
flat.push(dataNew);
|
||||
flat = flat.concat(that.treeToFlat(item1[childrenKey], item1[customName.id], dataIndex));
|
||||
});
|
||||
|
@ -1761,10 +1762,10 @@ layui.define(['table'], function (exports) {
|
|||
that.setRowCheckedClass(checkboxElem.closest('tr'), checked);
|
||||
|
||||
// 设置原始复选框 checked 属性值并渲染
|
||||
form.render(checkboxElem.prop({
|
||||
checkboxElem.prop({
|
||||
checked: checked,
|
||||
indeterminate: itemP[LAY_CHECKBOX_HALF]
|
||||
}))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1793,10 +1794,10 @@ layui.define(['table'], function (exports) {
|
|||
}
|
||||
|
||||
isIndeterminate = isIndeterminate && !isAll;
|
||||
form.render(tableView.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({
|
||||
tableView.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({
|
||||
'checked': isAll,
|
||||
indeterminate: isIndeterminate
|
||||
}));
|
||||
})
|
||||
|
||||
return isAll
|
||||
}
|
||||
|
@ -1908,7 +1909,7 @@ layui.define(['table'], function (exports) {
|
|||
|
||||
// 取消当前选中行背景色
|
||||
that.setRowCheckedClass(radioElem.closest('tr'), false);
|
||||
form.render(radioElem.prop('checked', false));
|
||||
radioElem.prop('checked', false);
|
||||
}
|
||||
}); // 取消其他的选中状态
|
||||
trData[checkName] = checked;
|
||||
|
@ -1916,7 +1917,7 @@ layui.define(['table'], function (exports) {
|
|||
that.setRowCheckedClass(trElem, checked); // 标记当前选中行背景色
|
||||
that.setRowCheckedClass(trElem.siblings(), false); // 取消其他行背景色
|
||||
|
||||
form.render(trElem.find('input[type="radio"][lay-type="layTableRadio"]').prop('checked', checked));
|
||||
trElem.find('input[type="radio"][lay-type="layTableRadio"]').prop('checked', checked);
|
||||
} else {
|
||||
// 切换只能用到单条,全选到这一步的时候应该是一个确定的状态
|
||||
checked = layui.type(checked) === 'boolean' ? checked : !trData[checkName]; // 状态切换,如果遇到不可操作的节点待处理 todo
|
||||
|
@ -1935,7 +1936,7 @@ layui.define(['table'], function (exports) {
|
|||
}).join(','));
|
||||
|
||||
that.setRowCheckedClass(checkboxElem.closest('tr'), checked); // 标记当前选中行背景色
|
||||
form.render(checkboxElem.prop({checked: checked, indeterminate: false}));
|
||||
checkboxElem.prop({checked: checked, indeterminate: false});
|
||||
|
||||
var trDataP;
|
||||
|
||||
|
@ -1944,7 +1945,7 @@ layui.define(['table'], function (exports) {
|
|||
// 找到父节点,然后判断父节点的子节点是否全部选中
|
||||
trDataP = that.getNodeDataByIndex(trData[LAY_PARENT_INDEX]);
|
||||
}
|
||||
|
||||
|
||||
return that.updateCheckStatus(trDataP, checked);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue