mirror of
https://gitee.com/layui/layui.git
synced 2025-04-04 23:39:34 +08:00
Merge branch 'main' into 2.10-dev
This commit is contained in:
commit
c112285cb3
4
.github/ISSUE_TEMPLATE/bug-feature.yml
vendored
4
.github/ISSUE_TEMPLATE/bug-feature.yml
vendored
@ -1,6 +1,10 @@
|
||||
name: 😄 创建议题
|
||||
description: 此处只受理 Bug 报告、功能请求。若是其他业务相关的问题建议在 Discussions 寻求社区帮助。
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> 💡 请遵循标题格式:**[组件名称] 描述问题的标题** ( 例如:[table] 表格能否支持自定义请求 )
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: 议题条件
|
||||
|
2
dist/css/layui.css
vendored
2
dist/css/layui.css
vendored
File diff suppressed because one or more lines are too long
2
dist/css/layui.css.map
vendored
2
dist/css/layui.css.map
vendored
File diff suppressed because one or more lines are too long
2
dist/layui.js
vendored
2
dist/layui.js
vendored
File diff suppressed because one or more lines are too long
2
dist/layui.js.map
vendored
2
dist/layui.js.map
vendored
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
Block a user