Compare commits

...

32 Commits

Author SHA1 Message Date
贤心
77adc3d196 release: v2.11.4 2025-06-22 22:18:22 +08:00
贤心
5a2baf9375
refactor(collapse): 重构折叠面板组件 (#2734) 2025-06-22 22:10:35 +08:00
贤心
ece68e117e release: v2.11.3 2025-06-18 10:34:19 +08:00
贤心
c7bfc564ea docs(tabs): 新增「打乱标签顺序」示例 2025-06-18 10:29:35 +08:00
贤心
e67266260f
feat(collapse): 新增折叠面板展开和收缩时的过渡动画 (#2722) 2025-06-17 15:17:20 +08:00
morning-star
e3f683cdc0
feat(treeTable): expandNode 新增 done 回调 (#2721)
* feat(treeTable): expandNode 新增 done 回调

* docs(treeTable): 更新文档

* update code

* Update docs/treeTable/index.md
2025-06-17 15:10:16 +08:00
贤心
1eb01c6706
fix(tabs): 优化 close 方法在标签顺序打乱时传入 lay-id 的支持 (#2690)
* fix(tabs): 优化 close 方法在标签顺序打乱时传入 lay-id 的支持

* fix(tabs): 优化 closeMult 方法 index 参数值为 lay-id 时的无效问题

* fix(tabs): 优化 `getHeaderItem` 等方法的 `index` 参数的类型检测
2025-06-17 15:09:36 +08:00
贤心
ac8d5ccc30 release: v2.11.2
Some checks failed
Issue Close Require / issue-close-require (push) Has been cancelled
2025-05-15 11:05:05 +08:00
corededitor
1ea5f34600
feat(tabs): 优化若干功能 (#2680) 2025-05-15 10:42:02 +08:00
morning-star
fe7df50ce7
fix(form-select): 修复 option 两端的 Unicode 空格(U+00A0)被去除的问题 (#2676)
* fix(form-select): 修复 option 两端的 Unicode 空格(U+00A0)被去除的问题

* update

* update

* fix
2025-05-15 10:32:04 +08:00
贤心
1b9557cdd8 feat(tabs): 增强若干功能 2025-05-13 00:19:59 +08:00
贤心
7138198645 fix(tabs): 优化 header 初始值判断,允许数组为空 2025-05-12 16:25:55 +08:00
贤心
a7af177223 release: v2.11.1
Some checks failed
Issue Close Require / issue-close-require (push) Has been cancelled
2025-05-06 15:43:25 +08:00
贤心
36a5beaa46
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>
2025-05-06 15:33:31 +08:00
Session小胡
c1d821d38d
perf(css): use transform in carousel (#2654) 2025-05-06 15:32:54 +08:00
morning-star
008e6cb7d0
fix(form-select): 修复 checkbox/radio 在 WebKit/537.36 的异常 (#2637)
* fix(form-select): 修复 `checkbox/radio` 在 WebKit/537.36 的异常

* docs: 优化部分注释文案,避免非技术人员理解错位

尽量避免词汇:监听、侦听。可用事件「触发」或「响应」等相近含义的词语替代

* Revert "docs: 优化部分注释文案,避免非技术人员理解错位"

This reverts commit 8cc9949bdfa36a3ff052bbdd95beea26fd3793ce.

---------

Co-authored-by: 贤心 <3277200+sentsim@users.noreply.github.com>
2025-05-06 14:51:38 +08:00
贤心
fe5e4e1264 docs: 有些部分文档细节 2025-04-26 23:22:04 +08:00
贤心
4fd021e48b release: v2.11.0
Some checks failed
Issue Close Require / issue-close-require (push) Has been cancelled
2025-04-21 15:56:23 +08:00
贤心
5e7cbdeb30 release: v2.11.0-rc.5 2025-04-21 00:32:38 +08:00
morning-star
b3bfc92374
fix(layui): 修复 layui.link 重复执行时不触发回调函数的问题 (#2651)
* fix(layui.js): 修复 layui.link 重复执行时回调不触发的问题

这会导致 laydate 无法渲染,行为和 2.9 保持一致

* chore(link): 修改注释错别字

* chore(link): 添加注释

---------

Co-authored-by: 贤心 <3277200+sentsim@users.noreply.github.com>
2025-04-21 00:22:53 +08:00
贤心
985803ec09
feat(laytpl): 增强 template 报错时的上下文捕获 (#2650)
* fix(laytpl): 优化接口输出顺序,避免 vite 中无法向 layui 输出接口

* feat(laytpl): 增强 template 错误行上下文捕获
2025-04-21 00:21:48 +08:00
贤心
6d524c0674 release: v2.11.0-rc.4 2025-04-18 21:50:07 +08:00
morning-star
23a62619d9
fix(laytpl): 兼容性调整 (#2647)
避免部分组件受全局 laytpl tagStyle 影响
2025-04-18 21:35:30 +08:00
贤心
a7267a4b5d
chore(hash): 新增返回 pathname, 与 layui.url 一致 (#2649)
`path` 将在合适的版本移除
2025-04-18 21:04:38 +08:00
贤心
3617209874
fix(component): 优化 render, events 执行的条件 (#2643) 2025-04-17 23:16:17 +08:00
贤心
1f2fc91431
style(css): 清理 IE 低版本 css hack (#2642) 2025-04-17 23:16:02 +08:00
morning-star
6fc761e63b
chore(laytpl): 兼容性调整 (#2638) 2025-04-17 23:12:06 +08:00
morning-star
a1e084c6b4
feat(form-select): select 点击外部关闭支持检测 iframe (#2631)
* feat(lay): lay.onClickoutside 新增 detectIframe 选项

* feat(form-select): select 支持检测 iframe 点击

* feat(lay): lay.touchSwipe 新增 preventDefault 选项

* docs: 优化部分注释文案,避免非技术人员理解错位

尽量避免词汇:监听、侦听。可用事件「触发」或「响应」等相近含义的词语替代

---------

Co-authored-by: 贤心 <3277200+sentsim@users.noreply.github.com>
2025-04-17 23:11:41 +08:00
morning-star
3842a98360
feat(dropdown): onClickoutside 检测 iframe 区域 (#2629) 2025-04-17 23:08:57 +08:00
贤心
a060a484e4 release: v2.11.0-rc.3 2025-04-15 14:59:09 +08:00
贤心
d2e01d0491 docs(versions): 添加 v2.9.26 更新日志 2025-04-15 13:46:01 +08:00
贤心
78438c3429
fix: 优化 escape 和 unescape 在解析某些特殊字符串时的潜在问题 (#2628)
* fix: 修复 escape 未转义 unicode 中 & 字符的问题

* chore: update

* fix: 优化 unescape 替换顺序,确保为 escape 替换的反向顺序

* chore: update
2025-04-15 13:23:32 +08:00
36 changed files with 952 additions and 438 deletions

2
dist/css/layui.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
dist/layui.js vendored

File diff suppressed because one or more lines are too long

2
dist/layui.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -299,5 +299,5 @@ Class.prototype.xxx = function() {
## 💖 心语 ## 💖 心语
Layui 由于早前欠缺统筹性思维,很多组件自成一体,使得无法对组件进行很好的统一管理。随着版本的迭代,我们也一直在努力尝试改善这一问题,但很多时候,为了向下兼容而不得不保留许多旧有的特性。`component` 模块的初衷正是为了确保组件的一致性,如核心逻辑和 API 设计等,其目的也是为了让 2.x 系列版本尽可能地减少些遗憾,让 Layui 在既定的范式中保持前行 一直以来Layui 的很多组件自成一体,使得无法对组件进行较好的统一管理。尽管我们也曾努力尝试改善这个问题,但很多时候为了向下兼容而又不得不保留许多旧有的特性,随着组件的增加,该问题也显得越加明显。而 component 模块的出现,将在一定程度上填补这一缺憾,它的初衷正是为了确保 Layui 组件的一致性,如核心逻辑和 API 设计等,主要意义在于:**给 Layui 2 系列版本提供一个构建通用组件的方式**,增强其「生命力」

View File

@ -33,7 +33,7 @@
&lt;textarea id="ID-tpl-data"&gt; &lt;textarea id="ID-tpl-data"&gt;
{ {
"title": "Layui 常用组件", "title": "Layui 常用组件",
"desc": "<a style=\"color:blue;\">一段带 HTML 内容的描述</a>", "desc": "<a style=\"color:blue;\">一段带 HTML 内容</a>",
"list": [ "list": [
{ {
"title": "弹层", "title": "弹层",

View File

@ -57,8 +57,8 @@ toc: true
<div class="layui-collapse"> <div class="layui-collapse">
<div class="layui-colla-item"> <div class="layui-colla-item">
<div class="layui-colla-title">Collapse Title 1</div> <div class="layui-colla-title">Collapse Title 1</div>
<div class="layui-colla-content"> <div class="layui-colla-content layui-show">
<p>Content 1</p> <p>Content 1 (添加 layui-show 类设置初始展开)</p>
</div> </div>
</div> </div>
<div class="layui-colla-item"> <div class="layui-colla-item">

View File

@ -38,6 +38,16 @@
</textarea> </textarea>
</pre> </pre>
<h3 id="demo-shuffle" lay-toc="{level: 2}">打乱标签顺序</h3>
<pre class="layui-code" lay-options="{preview: true, layout: ['preview', 'code'], codeStyle: 'max-height: 520px;', tools: ['full'], done: function(obj){
obj.render();
}}">
<textarea>
{{- d.include("/tabs/examples/shuffle.md") }}
</textarea>
</pre>
<h3 id="demo-hash" lay-toc="{level: 2, title: 'HASH 匹配'}">通过 HASH 匹配选中标签</h3> <h3 id="demo-hash" lay-toc="{level: 2, title: 'HASH 匹配'}">通过 HASH 匹配选中标签</h3>
切换 tabs 标签项后,地址栏同步 `hash`当页面刷新时tabs 仍保持对应的切换状态。 切换 tabs 标签项后,地址栏同步 `hash`当页面刷新时tabs 仍保持对应的切换状态。

View File

@ -89,13 +89,12 @@ layui.use(function() {
title: 'New Tab '+ n, // 此处加 n 仅为演示区分,实际应用不需要 title: 'New Tab '+ n, // 此处加 n 仅为演示区分,实际应用不需要
content: 'New Tab Content '+ n, content: 'New Tab Content '+ n,
id: 'new-'+ n, id: 'new-'+ n,
aaa: 'attr-'+ n, // 自定义属性,其中 aaa 可任意命名 done: function(data) {
done: function(params) { console.log(data); // 查看返回的参数
console.log(params); // 查看返回的参数
// 给新标签头添加上下文菜单 // 给新标签头添加上下文菜单
dropdown.render($.extend({}, dropdownInst.config, { dropdown.render($.extend({}, dropdownInst.config, {
elem: params.thisHeaderItem // 当前标签头元素 elem: data.headerItem // 新标签头元素 --- headerItem 为 2.11.2 新增
})); }));
} }
}, opts); }, opts);

View File

@ -0,0 +1,22 @@
<div class="layui-tabs" lay-options="{closable: true}">
<ul class="layui-tabs-header">
<li lay-id="fff">Tab6</li>
<li lay-id="eee">Tab5</li>
<li lay-id="ccc">Tab3</li>
<li lay-id="bbb">Tab2</li>
<li lay-id="aaa">Tab1</li>
<li lay-id="ddd">Tab4</li>
</ul>
<div class="layui-tabs-body">
<div class="layui-tabs-item" lay-id="aaa">Tab Content-1</div>
<div class="layui-tabs-item" lay-id="bbb">Tab Content-2</div>
<div class="layui-tabs-item" lay-id="ccc">Tab Content-3</div>
<div class="layui-tabs-item" lay-id="ddd">Tab Content-4</div>
<div class="layui-tabs-item" lay-id="eee">Tab Content-5</div>
<div class="layui-tabs-item" lay-id="fff">Tab Content-6</div>
</div>
</div>
🔔 提示:即 tabs 能通过 `lay-id` 匹配对应的标签头和标签内容。
<!-- import layui -->

View File

@ -122,6 +122,12 @@ tabs.render({
tabs.add('test', { tabs.add('test', {
title: 'New Tab 1', title: 'New Tab 1',
content: 'New Tab Content 1', content: 'New Tab Content 1',
done: function(data) {
console.log(data); // 标签相关数据
// 为新标签头添加任意属性
data.headerItem.attr('lay-tips', '111');
}
}); });
``` ```
@ -130,7 +136,7 @@ tabs.add('test', {
`tabs.close(id, index, force)` `tabs.close(id, index, force)`
- 参数 `id` : 组件的实例 ID - 参数 `id` : 组件的实例 ID
- 参数 `index` : 标签索引或标签的 `lay-id` 属性值 - 参数 `index` : 若传入 number 类型,则为标签索引;若传入 string 类型,则为标签的 `lay-id` 属性值
- 参数 `force` : 是否强制关闭。若设置 `true` 将忽略 `beforeClose` 事件行为。默认 `false` - 参数 `force` : 是否强制关闭。若设置 `true` 将忽略 `beforeClose` 事件行为。默认 `false`
该方法用于关闭指定的标签项。 该方法用于关闭指定的标签项。
@ -150,19 +156,23 @@ tabs.close('test', 'abc'); // 关闭 lay-id="abc" 的标签
| mode | 描述 | | mode | 描述 |
| --- | --- | | --- | --- |
| other | 关闭除当前标签外的所有标签 | | other | 关闭除当前标签外的其他标签 |
| right | 关闭当前标签及右侧标签 | | right | 关闭当前标签的右侧所有标签 |
| all | 关闭所有标签 | | all | 关闭所有标签 |
- 参数 `index` : 活动标签的索引或 `lay-id` 属性值,默认取当前选中标签的索引。一般用于标签右键事件。 - 参数 `index` : 活动标签的索引或 `lay-id` 属性值,默认取当前选中标签的索引。一般用于标签右键事件。
该方法用于批量关闭标签。 该方法用于批量关闭标签,若标签项已设置不允许关闭(`lay-closable="false"`),则操作将被忽略
```js ```js
tabs.closeMult(id, 'other'); // 关闭除当前标签外的所有标签 tabs.closeMult(id, 'other'); // 关闭除当前活动标签外的其他标签
tabs.closeMult(id, 'other', 3); // 关闭除索引为 3 的标签外的所有标签 tabs.closeMult(id, 'other', 3); // 关闭除索引为 3 的标签外的其他标签
tabs.closeMult(id, 'right'); // 关闭当前标签及右侧标签 tabs.closeMult(id, 'other', 'ccc'); // 关闭除 lay-id="ccc" 的标签外的其他标签
tabs.closeMult(id, 'right'); // 关闭当前活动标签的右侧所有标签
tabs.closeMult(id, 'right', 3); // 关闭索引为 3 的标签的右侧所有标签 tabs.closeMult(id, 'right', 3); // 关闭索引为 3 的标签的右侧所有标签
tabs.closeMult(id, 'right', 'ccc'); // 关闭 lay-id="ccc" 的标签的右侧所有标签
tabs.closeMult(id, 'all'); // 关闭所有标签 tabs.closeMult(id, 'all'); // 关闭所有标签
``` ```
@ -202,10 +212,10 @@ console.log(data);
{ {
options, // 标签配置信息 options, // 标签配置信息
container, // 标签容器的相关元素 container, // 标签容器的相关元素
thisHeaderItem, // 当前标签头部项 thisHeaderItem, // 当前活动标签头部项
thisBodyItem, // 当前标签内容项 thisBodyItem, // 当前活动标签内容项
index, // 当前标签索引 index, // 当前活动标签索引
length, // 当前标签数 length, // 标签数
} }
``` ```
@ -214,12 +224,13 @@ console.log(data);
`tabs.getHeaderItem(id, index)` `tabs.getHeaderItem(id, index)`
- 参数 `id` : 组件的实例 ID - 参数 `id` : 组件的实例 ID
- 参数 `index` : 标签索引或标签的 `lay-id` 属性值 - 参数 `index` : 若传入 number 类型,则为标签索引;若传入 string 类型,则为标签的 `lay-id` 属性值
该方法用于获取标签头部项元素。 该方法用于获取标签头部项元素。
```js ```js
var headerItem = tabs.getHeaderItem('test', 3); // 获取索引为 3 的标签头部项元素 var headerItem = tabs.getHeaderItem('test', 3); // 获取索引为 3 的标签头部项元素
var headerItem = tabs.getHeaderItem('test', 'abc'); // 获取 lay-id="abc" 的标签头部项元素
``` ```
<h3 id="getBodyItem" class="ws-anchor ws-bold">获取标签内容项</h3> <h3 id="getBodyItem" class="ws-anchor ws-bold">获取标签内容项</h3>
@ -227,12 +238,13 @@ var headerItem = tabs.getHeaderItem('test', 3); // 获取索引为 3 的标签
`tabs.getBodyItem(id, index)` `tabs.getBodyItem(id, index)`
- 参数 `id` : 组件的实例 ID - 参数 `id` : 组件的实例 ID
- 参数 `index` : 标签索引或标签的 `lay-id` 属性值 - 参数 `index` : 若传入 number 类型,则为标签索引;若传入 string 类型,则为标签的 `lay-id` 属性值 <sup>2.11.2+</sup>
该方法用于获取标签内容项元素。 该方法用于获取标签内容项元素。
```js ```js
var bodyItem = tabs.getBodyItem('test', 3); // 获取索引为 3 的标签内容项元素 var bodyItem = tabs.getBodyItem('test', 3); // 获取索引为 3 的标签内容项元素
var bodyItem = tabs.getBodyItem('test', 'abc'); // 获取 lay-id="abc" 的标签内容项元素
``` ```
<h3 id="refresh" class="ws-anchor ws-bold">刷新标签视图</h3> <h3 id="refresh" class="ws-anchor ws-bold">刷新标签视图</h3>

View File

@ -274,7 +274,8 @@ treeTable.addNodes('test', {
| index | 节点对应的行下标,一般可通过 `<tr>` 元素的 `data-index` 属性获得 | number | - | | index | 节点对应的行下标,一般可通过 `<tr>` 元素的 `data-index` 属性获得 | number | - |
| expandFlag | 设置展开或关闭状态,若为 `true` 则表示展开;`false` 则为关闭;`null` 则表示切换 | boolean/null | - | | expandFlag | 设置展开或关闭状态,若为 `true` 则表示展开;`false` 则为关闭;`null` 则表示切换 | boolean/null | - |
| inherit | 子节点是否继承父节点的展开或关闭状态,`expandFlag` 属性必须为 `boolean` 型时才有效。 | boolean | `false` | | inherit | 子节点是否继承父节点的展开或关闭状态,`expandFlag` 属性必须为 `boolean` 型时才有效。 | boolean | `false` |
| callbackFlag | 是否触发事件(`beforeExpand,onExpand` | boolean | `false` | | callbackFlag | 是否触发 tree.callback 事件(`beforeExpand,onExpand` | boolean | `false` |
| done <sup>2.11.3+</sup>| 节点操作完成后的回调函数 | (tableId, trData, trExpand) => void | - |
若操作的节点不是一个父节点,则返回 `null`,否则返回操作之后的折叠状态。 若操作的节点不是一个父节点,则返回 `null`,否则返回操作之后的折叠状态。

View File

@ -11,6 +11,110 @@ toc: true
<h2 id="2.10+" lay-toc="{title: '2.10+'}"></h2> <h2 id="2.10+" lay-toc="{title: '2.10+'}"></h2>
<h2 id="v2.11.4" lay-pid="2.10+" class="ws-anchor">
v2.11.4
<span class="layui-badge-rim">2025-06-23</span>
<span class="layui-badge-rim" style="color: #16b777;">稳定版</span>
</h2>
- 重构 collapse 展开收缩动画的核心逻辑 #2734
- 新增 collapse 列表项添加 `layui-show` 类设置默认展开的支持,且兼容旧版 #2734
- 修复 collapse 列表项的内容元素添加 `layui-show` 类时的收缩异常问题 #2734
### 下载: [layui-v2.11.4.zip](https://gitee.com/layui/layui/attach_files/2241193/download)
---
<h2 id="v2.11.3" lay-pid="2.10+" class="ws-anchor">
v2.11.3
<span class="layui-badge-rim">2025-06-18</span>
</h2>
- #### tabs
- 优化 `close` 方法在标签顺序打乱时传入 `lay-id` 的支持 #2690 @sentsim
- 优化 `closeMult` 方法的 `index` 参数值为 `lay-id` 时的无效问题 #2690 @sentsim
- 优化 `getHeaderItem` 等方法的 `index` 参数的类型检测 #2690 @sentsim
- #### treeTable
- 新增 `expandNode` 方法的 `done` 回调 #2721 @Sight-wcg
- #### collapse
- 新增 折叠面板展开和收缩时的过渡动画 #2722 @sentsim
### 下载: [layui-v2.11.3.zip](https://gitee.com/layui/layui/attach_files/2233291/download)
---
<h2 id="v2.11.2" lay-pid="2.10+" class="ws-anchor">
v2.11.2
<span class="layui-badge-rim">2025-05-15</span>
</h2>
- #### form-select
- 修复 `<option>` 文本两端的 Unicode 空格(U+00A0)被去除的问题 #2676 @Sight-wcg
- #### tabs
- 优化 `header` 选项初始值的判断,允许数组为空 #2680 @sentsim
- 优化 `tabs.getBodyItem()` 第二个参数,可接受索引或 `lay-id`#2680
- 优化 `tabs.add()``done` 回调,参数新增包含新标签项元素 #2680
- 优化 `tabs.change()` 方法,标签项打乱顺序时仍可通过 `lay-id` 切换 #2680
### 下载: [layui-v2.11.2.zip](https://gitee.com/layui/layui/attach_files/2189123/download)
---
<h2 id="v2.11.1" lay-pid="2.10+" class="ws-anchor">
v2.11.1
<span class="layui-badge-rim">2025-05-06</span>
</h2>
- 修复 select 组件的字符转义问题 #2661 @sentsim
- 修复 checkbox/radio 在 WebKit/537.36 的异常 #2637 @Sight-wcg
- 优化 carousel 切换时的动画性能 #2654 @SessionHu
### 下载: [layui-v2.11.1.zip](https://gitee.com/layui/layui/attach_files/2177069/download)
---
<h2 id="v2.11.0" lay-pid="2.10+" class="ws-anchor">
v2.11.0
<span class="layui-badge-rim">2025-04-21</span>
</h2>
- #### 新特性
- 新增 无缝扩展任意外部模块的支持,及优化大量核心 #2560 @sentsim
- 重构 laytpl 模板引擎,增强对更多复杂模板结构的解析能力 #2577 @sentsim
- #### Core
- 新增 `layui.extend()` 无缝扩展任意外部模块的支持,即无需遵循 Layui 模块规范的第三方模块
- 优化 `layui.use(), layui.link()` 核心逻辑
- 优化 `layui.js` 整体代码风格
- #### [laytpl](./laytpl/)
- 新增 `cache` 选项,用于是否开启模板缓存
- 新增 `condense` 选项,用于是否压缩模板空白符,如将多个连续的空白符压缩为单个空格
- 新增 `tagStyle` 选项,用于设置标签风格。默认仍采用 `< 2.11` 版本风格
- 新增 `laytpl.extendVars()` 方法,用于扩展模板内部变量
- 新增 `compile` 实例方法,用于清除缓存后以便渲染时重新对模板进行编译
- 新增 在模板中通过 `include()` 方法导入子模板的功能
- 新增 新的标签风格:{{!`{{ 语句 }}` `{{= 转义输出 }}` `{{- 原文输出 }}` `{{# 注释 }}`!}}
- 新增 template 报错时的上下文捕获,基于映射,可更精确定位到模板具体错误行 #2650 @sentsim
- 提升 模板解析的整体性能及稳定性
- 内置 对多种模块加载方式的支持,以同时适配 Node.js 和浏览器端的使用场景
- #### rate
- 重构 组件代码结构,由 component 模块构建,并继承其全部基础接口 #2626 @sentsim
- #### component
- 剔除 `isRenderOnEvent, isRenderWithoutElem` 实验型选项 #2625 @sentsim
- #### tabs
- 新增 `tabs.add()``active` 选项,用于是否将新增项设置为活动标签 #2607 @lanrenbulan
- 修复 `box-sizing` 对主体区域中其他组件的样式影响 #2622 @sentsim
- #### 其他
- 新增 dropdown 可点击面板外部 iframe 区域关闭的功能 #2629 @Sight-wcg
- 新增 select 可点击面板外部 iframe 区域关闭的功能 #2631 @Sight-wcg
- 新增 layui.hash() 返回的成员 `pathname`, 与 layui.url() 一致 #2649 @sentsim
- 优化 card 面板头部样式,去除高度限制 #2621 @sentsim
- 优化 laypage 快速点击时文本被选中的问题 #2623 @sentsim
- 优化 util 的 `escape``unescape` 在解析某些特殊字符串时的潜在问题 #2628 @sentsim
### 下载: [layui-v2.11.0.zip](https://gitee.com/layui/layui/attach_files/2158121/download)
---
<h2 id="v2.10.3" lay-pid="2.10+" class="ws-anchor"> <h2 id="v2.10.3" lay-pid="2.10+" class="ws-anchor">
v2.10.3 v2.10.3
<span class="layui-badge-rim">2025-03-30</span> <span class="layui-badge-rim">2025-03-30</span>

View File

@ -17,6 +17,20 @@ toc: true
<h2 id="2.9.x" lay-toc="{title: '2.9.x'}"></h2> <h2 id="2.9.x" lay-toc="{title: '2.9.x'}"></h2>
<h2 id="v2.9.26" class="ws-anchor">
v2.9.26
<span class="layui-badge-rim">2025-04-15</span>
<span class="layui-badge-rim" style="color: #16b777;">稳定版</span>
</h2>
- 优化 util 的 `escape``unescape` 在解析某些特殊字符串时的潜在问题 #2628 @sentsim
- 修复 layer.photos 在空图片容器动态添加图片时,无法获取 data 的问题 #2581 @Sight-wcg
- 修复 body 初始 `line-height` 无效的问题 #2569 @sentsim
### 下载: [layui-v2.9.26.zip](https://gitee.com/layui/layui/attach_files/2149661/download)
---
<h2 id="v2.9.25" lay-pid="2.9.x" class="ws-anchor"> <h2 id="v2.9.25" lay-pid="2.9.x" class="ws-anchor">
v2.9.25 v2.9.25
<span class="layui-badge-rim">2025-03-13</span> <span class="layui-badge-rim">2025-03-13</span>

89
examples/collapse.html Normal file
View File

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>折叠面板 - Layui</title>
<link rel="stylesheet" href="../src/css/layui.css">
</head>
<body class="layui-padding-3">
<h2>常规用法:</h2><br>
<div class="layui-collapse" lay-filter="test">
<div class="layui-colla-item">
<h3 class="layui-colla-title">item 1</h3>
<div class="layui-colla-content layui-show">
旧版,通过给列表的内容添加 layui-show 类开启显示
</div>
</div>
<div class="layui-colla-item">
<h3 class="layui-colla-title">item2</h3>
<div class="layui-colla-content">
content 2
</div>
</div>
<div class="layui-colla-item">
<h3 class="layui-colla-title">item 3</h3>
<div class="layui-colla-content">
content 3
</div>
</div>
</div>
<br>
<div class="layui-collapse" lay-filter="test">
<div class="layui-colla-item layui-show">
<h3 class="layui-colla-title">item 111</h3>
<div class="layui-colla-content">
新版 <sup>2.11.4+</sup>,通过给列表项直接添加 layui-show 类开启显示
</div>
</div>
<div class="layui-colla-item">
<h3 class="layui-colla-title">item 222</h3>
<div class="layui-colla-content">
content 2
</div>
</div>
<div class="layui-colla-item">
<h3 class="layui-colla-title">item 333</h3>
<div class="layui-colla-content">
content 3
</div>
</div>
</div>
<br><h2>开启手风琴:</h2><br>
<div class="layui-collapse" lay-accordion>
<div class="layui-colla-item layui-show">
<h3 class="layui-colla-title">item 1</h3>
<div class="layui-colla-content">
旧版,通过给列表的内容添加 layui-show 类开启显示
</div>
</div>
<div class="layui-colla-item">
<h3 class="layui-colla-title">item2</h3>
<div class="layui-colla-content">
content 2
</div>
</div>
<div class="layui-colla-item">
<h3 class="layui-colla-title">item 3</h3>
<div class="layui-colla-content">
content 3
</div>
</div>
</div>
<script src="../src/layui.js"></script>
<script>
layui.use('element', function(){
var element = layui.element;
element.on('collapse(test)', function(data){
console.log(data);
});
});
</script>
</body>
</html>

View File

@ -68,30 +68,7 @@ body{padding:20px;}
<span class="layui-badge-rim">Hot</span> <span class="layui-badge-rim">Hot</span>
<hr> <hr><br>
<div class="layui-collapse" lay-filter="test" lay-accordion>
<div class="layui-colla-item">
<h2 class="layui-colla-title">杜甫</h2>
<div class="layui-colla-content layui-show">
<p>杜甫的思想核心是儒家的仁政思想他有“致君尧舜上再使风俗淳”的宏伟抱负。杜甫虽然在世时名声并不显赫但后来声名远播对中国文学和日本文学都产生了深远的影响。杜甫共有约1500首诗歌被保留了下来大多集于《杜工部集》。</p>
</div>
</div>
<div class="layui-colla-item">
<h2 class="layui-colla-title">李清照</h2>
<div class="layui-colla-content">
<p>李清照出生于书香门第,早期生活优裕,其父李格非藏书甚富,她小时候就在良好的家庭环境中打下文学基础。出嫁后与夫赵明诚共同致力于书画金石的搜集整理。金兵入据中原时,流寓南方,境遇孤苦。所作词,前期多写其悠闲生活,后期多悲叹身世,情调感伤。形式上善用白描手法,自辟途径,语言清丽。</p>
</div>
</div>
<div class="layui-colla-item">
<h2 class="layui-colla-title">鲁迅</h2>
<div class="layui-colla-content">
<p>鲁迅一生在文学创作、文学批评、思想研究、文学史研究、翻译、美术理论引进、基础科学介绍和古籍校勘与研究等多个领域具有重大贡献。他对于五四运动以后的中国社会思想文化发展具有重大影响,蜚声世界文坛,尤其在韩国、日本思想文化领域有极其重要的地位和影响,被誉为“二十世纪东亚文化地图上占最大领土的作家”。</p>
</div>
</div>
</div>
<br><br>
<div class="layui-progress" lay-showPercent="true" lay-filter="demo-progress-1"> <div class="layui-progress" lay-showPercent="true" lay-filter="demo-progress-1">
<div class="layui-progress-bar" lay-percent="1/3"></div> <div class="layui-progress-bar" lay-percent="1/3"></div>
@ -174,19 +151,11 @@ body{padding:20px;}
灰色分割线 灰色分割线
<hr class="layui-border-gray"> <hr class="layui-border-gray">
<script src="../src/layui.js"></script> <script src="../src/layui.js"></script>
<script> <script>
layui.use('element', function() {
layui.use(['element', 'form'], function(){ var element = layui.element;
var element = layui.element;
element.on('collapse(test)', function(data){
console.log(data);
}); });
});
</script> </script>
</body> </body>
</html> </html>

View File

@ -200,8 +200,8 @@
<div class="layui-inline"> <div class="layui-inline">
<label class="layui-form-label">行内表单</label> <label class="layui-form-label">行内表单</label>
<div class="layui-input-block"> <div class="layui-input-block">
<select name="quiz" lay-verify="required" lay-vertype="tips" lay-filter="quiz111"> <select name="quiz" lay-verify="required" lay-vertype="tips" lay-filter="quiz">
<option value="">请"选择"问题</option> <option value="">请"选择"问题&nbsp;&nbsp;&nbsp;😀</option>
<option value="0">你工"作"的 第一个城市</option> <option value="0">你工"作"的 第一个城市</option>
<option value="1" disabled>你的工号</option> <option value="1" disabled>你的工号</option>
<option value="2"> <option value="2">
@ -213,7 +213,7 @@
<div class="layui-inline"> <div class="layui-inline">
<label class="layui-form-label">select分组</label> <label class="layui-form-label">select分组</label>
<div class="layui-input-block"> <div class="layui-input-block">
<select name="quiz" lay-filter="quiz"> <select name="quiz111" lay-filter="quiz111">
<option value="">请选择问题</option> <option value="">请选择问题</option>
<optgroup label="城市记忆"> <optgroup label="城市记忆">
<option value="0">你工作的第一个城市</option> <option value="0">你工作的第一个城市</option>
@ -245,7 +245,7 @@
<div class="layui-inline"> <div class="layui-inline">
<label class="layui-form-label">搜索选择框</label> <label class="layui-form-label">搜索选择框</label>
<div class="layui-input-block"> <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="写作">写"作"</option> <option value="写作">写"作"</option>
<option value="阅读" disabled>阅读</option> <option value="阅读" disabled>阅读</option>
@ -451,12 +451,12 @@
}); });
//事件 //事件
form.on('select(quiz111)', function(data){ form.on('select(quiz)', function(data){
console.log('select: ', this, data); console.log('select.quiz: ', this, data);
}); });
form.on('select(quiz)', function(data){ form.on('select(quiz111)', function(data){
console.log('select.quiz', this, data); console.log('select.quiz111', this, data);
}); });
form.on('select(interest)', function(data){ form.on('select(interest)', function(data){
@ -531,7 +531,7 @@
<div class="layui-inline" lay-ignore> <div class="layui-inline" lay-ignore>
<input type="checkbox" name="like[write]" title="写作"> <input type="checkbox" name="like[write]" title="写作">
<input type="radio" name="sex" value="1" title="男"> <input type="radio" name="sex" value="1" title="男">
<select name="quiz"> <select name="quiz111">
<option value="">请选择</option> <option value="">请选择</option>
<option value="AAAAA">AAAAA</option> <option value="AAAAA">AAAAA</option>
<option value="BBBBB">BBBBB</option> <option value="BBBBB">BBBBB</option>

View File

@ -90,6 +90,26 @@
</div> </div>
</div> </div>
<h2>打乱标签顺序:</h2>
<div class="layui-tabs" lay-options="{closable: true}">
<ul class="layui-tabs-header">
<li lay-id="fff">Tab6</li>
<li lay-id="eee">Tab5</li>
<li lay-id="ccc">Tab3</li>
<li lay-id="bbb">Tab2</li>
<li lay-id="aaa">Tab1</li>
<li lay-id="ddd">Tab4</li>
</ul>
<div class="layui-tabs-body">
<div class="layui-tabs-item" lay-id="aaa">Tab Content-1</div>
<div class="layui-tabs-item" lay-id="bbb">Tab Content-2</div>
<div class="layui-tabs-item" lay-id="ccc">Tab Content-3</div>
<div class="layui-tabs-item" lay-id="ddd">Tab Content-4</div>
<div class="layui-tabs-item" lay-id="eee">Tab Content-5</div>
<div class="layui-tabs-item" lay-id="fff">Tab Content-6</div>
</div>
</div>
<h2>标签 HASH 定位</h2> <h2>标签 HASH 定位</h2>
<div class="layui-tabs layui-hide-v" id="demoTabs-hash"> <div class="layui-tabs layui-hide-v" id="demoTabs-hash">
<ul class="layui-tabs-header"> <ul class="layui-tabs-header">
@ -167,27 +187,40 @@
<script src="../src/layui.js"></script> <script src="../src/layui.js"></script>
<script> <script>
layui.use(function() { layui.use(function() {
var $ = layui.$;
var tabs = layui.tabs var tabs = layui.tabs
var util = layui.util; var util = layui.util;
var layer = layui.layer; var layer = layui.layer;
var dropdown = layui.dropdown; var dropdown = layui.dropdown;
// 新增随机标签
var addTabs = function(opts) {
var n = Math.random()*1000 | 0; // 演示标记
opts = $.extend({
title: 'New Tab '+ n, // 此处加 n 仅为演示区分,实际应用不需要
content: 'New Tab Content '+ n,
id: 'new-'+ n,
// active: false, // 是否设为活动标签
done: function(data) {
console.log(data); // 查看返回的参数
// 为新标签头添加任意属性 --- 2.11.2+
data.headerItem.attr('lay-tips', 'tip-'+ n);
// 给新标签头添加上下文菜单
dropdown.render($.extend({}, dropdownInst.config, {
elem: data.headerItem // 新标签头元素
}));
}
}, opts);
// 添加标签到最后
tabs.add('demoTabs1', opts);
}
// 自定义事件 // 自定义事件
util.on({ util.on({
add: function(){ add: function(){
var n = Math.random()*1000 | 0; // 演示标记 addTabs();
//添加标签
tabs.add('demoTabs1', {
title: 'New Tab '+ n, // 此处加 n 仅为演示区分,实际应用不需要
content: 'New Tab Content '+ n,
id: 'new-'+ n,
aaa: 'attr-'+ n, // 自定义属性,其中 aaa 可任意命名
// mode: 'curr',
done: function(params) {
console.log(params);
}
});
} }
}); });
@ -226,30 +259,49 @@
}); });
// 为标签头添加上下文菜单 // 为标签头添加上下文菜单
dropdown.render({ var dropdownInst = dropdown.render({
elem: '#demoTabs1 .layui-tabs-header>li', elem: '#demoTabs1 .layui-tabs-header>li',
trigger: 'contextmenu', trigger: 'contextmenu',
data: [{ data: [{
title: '关闭', title: '在右侧新增标签页',
type: 'this' action: 'add',
}, { mode: 'after'
title: '关闭其他标签页',
type: 'other'
}, {
title: '关闭右侧标签页',
type: 'right'
}, { }, {
type: '-' type: '-'
}, {
title: '关闭',
action: 'close',
mode: 'this',
}, {
title: '关闭其他标签页',
action: 'close',
mode: 'other'
}, {
title: '关闭右侧标签页',
action: 'close',
mode: 'right'
}, { }, {
title: '关闭所有标签页', title: '关闭所有标签页',
type: 'all' action: 'close',
mode: 'all'
}], }],
click: function(data, othis, event) { click: function(data, othis, event) {
var index = this.elem.index(); var index = this.elem.index(); // 获取活动标签索引
if (data.type === 'this') { var layid = this.elem.attr('lay-id');
tabs.close('demoTabs1', index); // 关闭当前标签
} else { // 新增标签操作
tabs.closeMult('demoTabs1', data.type, index); // 批量关闭标签 if (data.action === 'add') {
// 在当前活动标签右侧新增标签页
addTabs({
mode: data.mode,
index: index
});
} else if(data.action === 'close') { // 关闭标签操作
if (data.mode === 'this') {
tabs.close('demoTabs1', index); // 关闭当前标签
} else {
tabs.closeMult('demoTabs1', data.mode, index); // 批量关闭标签
}
} }
} }
}); });
@ -258,7 +310,7 @@
tabs.render({ tabs.render({
elem: '#demoTabs2', elem: '#demoTabs2',
header: [ header: [
{ title: 'Tab1' }, { title: 'Tab1', closable: false },
{ title: 'Tab2' }, { title: 'Tab2' },
{ title: 'Tab3' } { title: 'Tab3' }
], ],
@ -267,9 +319,9 @@
{ content: 'Tab content 2' }, { content: 'Tab content 2' },
{ content: 'Tab content 3' } { content: 'Tab content 3' }
], ],
// index: 1, //初始选中项 // index: 1, // 初始选中项
// className: 'layui-tabs-card', // className: 'layui-tabs-card',
// closable: true closable: true
}); });

View File

@ -14,12 +14,17 @@
<div class="layui-fluid" style="padding: 15px;"> <div class="layui-fluid" style="padding: 15px;">
<button class="layui-btn" lay-on="asyncLoad">asyncLoad</button> <button class="layui-btn" lay-on="asyncLoad">asyncLoad</button>
<button class="layui-btn" lay-on="flatData">flatData</button> <button class="layui-btn" lay-on="flatData">flatData</button>
<button class="layui-btn" lay-on="expandNode">expandNode</button>
<button class="layui-btn" lay-on="unexpandNode">unexpandNode</button>
<table id="demo"></table> <table id="demo"></table>
</div> </div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Mock.js/1.0.0/mock-min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Mock.js/1.0.0/mock-min.js"></script>
<script src="../src/layui.js" src1="//cdnjs.cloudflare.com/ajax/libs/layui/2.9.7/layui.js" <script src="../src/layui.js" src1="//cdnjs.cloudflare.com/ajax/libs/layui/2.9.7/layui.js"
src1="https://cdn.jsdelivr.net/gh/layui/layui@879a9c629cc832f5b235d138adf164d74c34991b/src/layui.js"></script> src1="https://cdn.jsdelivr.net/gh/layui/layui@879a9c629cc832f5b235d138adf164d74c34991b/src/layui.js"></script>
<script> <script>
Mock.setup({
timeout: '100-300'
});
layui.use(["treeTable", "util"], function () { layui.use(["treeTable", "util"], function () {
var treeTable = layui.treeTable; var treeTable = layui.treeTable;
var util = layui.util; var util = layui.util;
@ -39,6 +44,11 @@
async: { async: {
enable: true, enable: true,
autoParam: ["parentId=id"] autoParam: ["parentId=id"]
},
callback: {
onExpand: function (tableId, trData, trExpand) {
console.log('onExpand', tableId, trData.id, trExpand);
}
} }
}, },
}, true) }, true)
@ -57,6 +67,28 @@
} }
}, },
}, true) }, true)
},
expandNode: function(){
treeTable.expandNode('demo', {
index: 0,
expandFlag: true,
inherit: true,
callbackFlag: true,
done: function (tableId, trData, trExpand) {
console.log('done', tableId, trData.id, trExpand);
}
})
},
unexpandNode: function(){
treeTable.expandNode('demo', {
index: 0,
expandFlag: false,
inherit: true,
callbackFlag: true,
done: function (tableId, trData, trExpand) {
console.log('done', tableId, trData.id, trExpand);
}
})
} }
}) })
@ -130,7 +162,7 @@
//var testDatas = getTreeData(rootNodes); //var testDatas = getTreeData(rootNodes);
Mock.mock(/getDatas/, "get", (config) => { Mock.mock(/getDatas/, "get", (config) => {
console.log(config); //console.log(config);
var params = layui.url(config.url); var params = layui.url(config.url);
var search = params.search; var search = params.search;
var parentId = search.parentId; var parentId = search.parentId;

View File

@ -1,6 +1,6 @@
{ {
"name": "layui", "name": "layui",
"version": "2.11.0-rc.2", "version": "2.11.4",
"description": "Classic modular Front-End UI library", "description": "Classic modular Front-End UI library",
"keywords": [ "keywords": [
"layui", "layui",

View File

@ -577,7 +577,9 @@ a cite{font-style: normal;}
.layui-colla-item:first-child{border-top: none;} .layui-colla-item:first-child{border-top: none;}
.layui-colla-title{position: relative; height: 42px; line-height: 42px; padding: 0 15px 0 35px; color: #333; background-color: #fafafa; cursor: pointer; font-size: 14px; overflow: hidden;} .layui-colla-title{position: relative; height: 42px; line-height: 42px; padding: 0 15px 0 35px; color: #333; background-color: #fafafa; cursor: pointer; font-size: 14px; overflow: hidden;}
.layui-colla-content{display: none; padding: 10px 15px; line-height: 1.6; color: #5F5F5F;} .layui-colla-content{display: none; padding: 10px 15px; line-height: 1.6; color: #5F5F5F;}
.layui-colla-icon{position: absolute; left: 15px; top: 0; font-size: 14px;} .layui-colla-icon{position: absolute; left: 15px; top: 50%; margin-top: -7px; font-size: 14px; line-height: normal; transition: all .2s;}
.layui-colla-item.layui-show > .layui-colla-title .layui-colla-icon{transform: rotate(90deg);}
.layui-colla-item.layui-show > .layui-colla-content{display: block;}
/* 卡片面板 */ /* 卡片面板 */
.layui-card{margin-bottom: 15px; border-radius: 2px; background-color: #fff; box-shadow: 0 1px 2px 0 rgba(0,0,0,.05);} .layui-card{margin-bottom: 15px; border-radius: 2px; background-color: #fff; box-shadow: 0 1px 2px 0 rgba(0,0,0,.05);}
@ -1504,13 +1506,13 @@ body .layui-table-tips .layui-layer-content{background: none; padding: 0; box-sh
.layui-carousel>*[carousel-item]>.layui-this, .layui-carousel>*[carousel-item]>.layui-this,
.layui-carousel>*[carousel-item]>.layui-carousel-prev, .layui-carousel>*[carousel-item]>.layui-carousel-prev,
.layui-carousel>*[carousel-item]>.layui-carousel-next{display: block} .layui-carousel>*[carousel-item]>.layui-carousel-next{display: block}
.layui-carousel>*[carousel-item]>.layui-this{left: 0;} .layui-carousel>*[carousel-item]>.layui-this{-webkit-transform: translateX(0);transform: translateX(0);}
.layui-carousel>*[carousel-item]>.layui-carousel-prev{left: -100%;} .layui-carousel>*[carousel-item]>.layui-carousel-prev{-webkit-transform: translateX(-100%);transform: translateX(-100%);}
.layui-carousel>*[carousel-item]>.layui-carousel-next{left: 100%;} .layui-carousel>*[carousel-item]>.layui-carousel-next{-webkit-transform: translateX(100%);transform: translateX(100%);}
.layui-carousel>*[carousel-item]>.layui-carousel-prev.layui-carousel-right, .layui-carousel>*[carousel-item]>.layui-carousel-prev.layui-carousel-right,
.layui-carousel>*[carousel-item]>.layui-carousel-next.layui-carousel-left{left: 0;} .layui-carousel>*[carousel-item]>.layui-carousel-next.layui-carousel-left{-webkit-transform: translateX(0);transform: translateX(0);}
.layui-carousel>*[carousel-item]>.layui-this.layui-carousel-left{left: -100%;} .layui-carousel>*[carousel-item]>.layui-this.layui-carousel-left{-webkit-transform: translateX(-100%);transform: translateX(-100%);}
.layui-carousel>*[carousel-item]>.layui-this.layui-carousel-right{left: 100%;} .layui-carousel>*[carousel-item]>.layui-this.layui-carousel-right{-webkit-transform: translateX(100%);transform: translateX(100%);}
/* 上下切换 */.layui-carousel[lay-anim="updown"] .layui-carousel-arrow{left: 50%!important; top: 20px; margin: 0 0 0 -18px;} /* 上下切换 */.layui-carousel[lay-anim="updown"] .layui-carousel-arrow{left: 50%!important; top: 20px; margin: 0 0 0 -18px;}
.layui-carousel[lay-anim="updown"] .layui-carousel-arrow[lay-type="add"]{top: auto!important; bottom: 20px;} .layui-carousel[lay-anim="updown"] .layui-carousel-arrow[lay-type="add"]{top: auto!important; bottom: 20px;}
@ -1519,13 +1521,13 @@ body .layui-table-tips .layui-layer-content{background: none; padding: 0; box-sh
.layui-carousel[lay-anim="updown"] .layui-carousel-ind li{display: block; margin: 6px 0;} .layui-carousel[lay-anim="updown"] .layui-carousel-ind li{display: block; margin: 6px 0;}
.layui-carousel[lay-anim="updown"]>*[carousel-item]>*{left: 0!important;} .layui-carousel[lay-anim="updown"]>*[carousel-item]>*{left: 0!important;}
.layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-this{top: 0;} .layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-this{-webkit-transform: translateY(0);transform: translateY(0);}
.layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-carousel-prev{top: -100%;} .layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-carousel-prev{-webkit-transform: translateY(-100%);transform: translateY(-100%);}
.layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-carousel-next{top: 100%;} .layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-carousel-next{-webkit-transform: translateY(100%);transform: translateY(100%);}
.layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-carousel-prev.layui-carousel-right, .layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-carousel-prev.layui-carousel-right,
.layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-carousel-next.layui-carousel-left{top: 0;} .layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-carousel-next.layui-carousel-left{-webkit-transform: translateY(0);transform: translateY(0);}
.layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-this.layui-carousel-left{top: -100%;} .layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-this.layui-carousel-left{-webkit-transform: translateY(-100%);transform: translateY(-100%);}
.layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-this.layui-carousel-right{top: 100%;} .layui-carousel[lay-anim="updown"]>*[carousel-item]>.layui-this.layui-carousel-right{-webkit-transform: translateY(100%);transform: translateY(100%);}
/* 渐显切换 */.layui-carousel[lay-anim="fade"]>*[carousel-item]>*{left: 0!important;} /* 渐显切换 */.layui-carousel[lay-anim="fade"]>*[carousel-item]>*{left: 0!important;}
.layui-carousel[lay-anim="fade"]>*[carousel-item]>.layui-carousel-prev, .layui-carousel[lay-anim="fade"]>*[carousel-item]>.layui-carousel-prev,

View File

@ -49,7 +49,6 @@ html #layuicss-skincodecss{display: none; position: absolute; width: 1989px;}
.layui-code-preview > .layui-code-view{margin: 0;} .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{position: relative; z-index: 1; margin-bottom: 0;}
.layui-code-preview .layui-code-item{display: none; border-top-width: 0;} .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{position: relative; padding: 16px;}
.layui-code-item-preview > iframe{position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;} .layui-code-item-preview > iframe{position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;}

View File

@ -1,7 +1,7 @@
/** /**
* laydate style * laydate style
*/ */
html #layuicss-laydate{display: none; position: absolute; width: 1989px;} html #layuicss-laydate{display: none; position: absolute; width: 1989px;}
@ -15,7 +15,7 @@ html #layuicss-laydate{display: none; position: absolute; width: 1989px;}
.layui-laydate-header *, .layui-laydate-header *,
.layui-laydate-content td, .layui-laydate-content td,
.layui-laydate-list li{transition-duration: .3s; -webkit-transition-duration: .3s;} .layui-laydate-list li{transition-duration: .3s; -webkit-transition-duration: .3s;}
.layui-laydate-shade{top: 0; left: 0; width: 100%; height: 100%; _height: expression(document.body.offsetHeight+"px"); position: fixed; _position: absolute; pointer-events: auto;} .layui-laydate-shade{top: 0; left: 0; width: 100%; height: 100%; position: fixed; pointer-events: auto;}
/* 微微往下滑入 */ /* 微微往下滑入 */
@keyframes laydate-downbit { @keyframes laydate-downbit {
@ -51,7 +51,7 @@ html #layuicss-laydate{display: none; position: absolute; width: 1989px;}
.laydate-time-text{cursor: default !important;} .laydate-time-text{cursor: default !important;}
/* 主体结构 */ /* 主体结构 */
.layui-laydate-content{position: relative; padding: 10px; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none;} .layui-laydate-content{position: relative; padding: 10px; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none;}
.layui-laydate-content table{border-collapse: collapse; border-spacing: 0;} .layui-laydate-content table{border-collapse: collapse; border-spacing: 0;}
.layui-laydate-content th, .layui-laydate-content th,
.layui-laydate-content td{width: 36px; height: 30px; padding: 0; text-align: center;} .layui-laydate-content td{width: 36px; height: 30px; padding: 0; text-align: center;}
@ -140,7 +140,7 @@ html #layuicss-laydate{display: none; position: absolute; width: 1989px;}
.layui-laydate-footer span[lay-type="date"]{color: #16b777;} .layui-laydate-footer span[lay-type="date"]{color: #16b777;}
.layui-laydate .layui-this,.layui-laydate .layui-this>div{background-color: #16b777 !important; color: #fff !important;} .layui-laydate .layui-this,.layui-laydate .layui-this>div{background-color: #16b777 !important; color: #fff !important;}
.layui-laydate .laydate-disabled, .layui-laydate .laydate-disabled,
.layui-laydate .laydate-disabled:hover{background:none !important; color: #d2d2d2 !important; cursor: not-allowed !important; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none;} .layui-laydate .laydate-disabled:hover{background:none !important; color: #d2d2d2 !important; cursor: not-allowed !important; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none;}
.layui-laydate .layui-this.laydate-disabled,.layui-laydate .layui-this.laydate-disabled>div{background-color: #eee !important} .layui-laydate .layui-this.laydate-disabled,.layui-laydate .layui-this.laydate-disabled>div{background-color: #eee !important}
.layui-laydate-content td>div{padding: 7px 0; height: 100%;} .layui-laydate-content td>div{padding: 7px 0; height: 100%;}

View File

@ -6,17 +6,17 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
/* common */ /* common */
.layui-layer-shade, .layui-layer{position:fixed; _position:absolute; pointer-events: auto;} .layui-layer-shade, .layui-layer{position:fixed; _position:absolute; pointer-events: auto;}
.layui-layer-shade{opacity: 0; transition: opacity .35s cubic-bezier(0.34, 0.69, 0.1, 1); top:0; left:0; width:100%; height:100%; _height:expression(document.body.offsetHeight+"px");} .layui-layer-shade{opacity: 0; transition: opacity .35s cubic-bezier(0.34, 0.69, 0.1, 1); top:0; left:0; width:100%; height:100%;}
.layui-layer{-webkit-overflow-scrolling: touch;} .layui-layer{-webkit-overflow-scrolling: touch;}
.layui-layer{top:150px; left: 0; margin:0; padding:0; background-color:#fff; -webkit-background-clip: content; border-radius: 2px; box-shadow: 1px 1px 50px rgba(0,0,0,.3);} .layui-layer{top:150px; left: 0; margin:0; padding:0; background-color:#fff; -webkit-background-clip: content; background-clip: content; border-radius: 2px; box-shadow: 1px 1px 50px rgba(0,0,0,.3);}
.layui-layer-close{position:absolute;} .layui-layer-close{position:absolute;}
.layui-layer-content{position:relative;} .layui-layer-content{position:relative;}
.layui-layer-border{border: 1px solid #B2B2B2; border: 1px solid rgba(0,0,0,.1); box-shadow: 1px 1px 5px rgba(0,0,0,.2);} .layui-layer-border{border: 1px solid #B2B2B2; border: 1px solid rgba(0,0,0,.1); box-shadow: 1px 1px 5px rgba(0,0,0,.2);}
.layui-layer-load{background:url("data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=") #fff center center no-repeat;} .layui-layer-load{background:url("data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=") #fff center center no-repeat;}
.layui-layer-setwin span, .layui-layer-setwin span,
.layui-layer-btn a{display: inline-block; vertical-align: middle; *display: inline; *zoom:1; } .layui-layer-btn a{display: inline-block; vertical-align: middle;}
.layui-layer-move{display: none; position: fixed; *position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; cursor: move; opacity: 0; filter:alpha(opacity=0); background-color: #fff; z-index: 2147483647;} .layui-layer-move{display: none; position: fixed; left: 0px; top: 0px; width: 100%; height: 100%; cursor: move; opacity: 0; filter:alpha(opacity=0); background-color: #fff; z-index: 2147483647;}
.layui-layer-resize{position: absolute; width: 15px; height: 15px; right: 0; bottom: 0; cursor: se-resize;} .layui-layer-resize{position: absolute; width: 15px; height: 15px; right: 0; bottom: 0; cursor: se-resize;}
/* 动画 */ /* 动画 */
@ -32,17 +32,27 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
} }
.layer-anim-00{-webkit-animation-name: layer-bounceIn;animation-name: layer-bounceIn} .layer-anim-00{-webkit-animation-name: layer-bounceIn;animation-name: layer-bounceIn}
@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown} @-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}
@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}
@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig} @-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}
@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}
.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}
@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft} @-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}
@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}
@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0px) rotate(0deg);transform:translateX(0px) rotate(0deg)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0px) rotate(0deg);-ms-transform:translateX(0px) rotate(0deg);transform:translateX(0px) rotate(0deg)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn} @-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0px) rotate(0deg);transform:translateX(0px) rotate(0deg)}}
@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0px) rotate(0deg);-ms-transform:translateX(0px) rotate(0deg);transform:translateX(0px) rotate(0deg)}}
.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}
@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn} @-webkit-keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}
@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}
.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}
@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}} @-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}
@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}
.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}
/* 从上往下 */ /* 从上往下 */
@keyframes layer-slide-down { @keyframes layer-slide-down {
@ -120,7 +130,7 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
/* 标题栏 */ /* 标题栏 */
.layui-layer-title{padding: 0 81px 0 16px; height: 50px; line-height: 50px; border-bottom:1px solid #F0F0F0; font-size: 14px; color:#333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-radius: 2px 2px 0 0;} .layui-layer-title{padding: 0 81px 0 16px; height: 50px; line-height: 50px; border-bottom:1px solid #F0F0F0; font-size: 14px; color:#333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-radius: 2px 2px 0 0;}
.layui-layer-setwin{position:absolute; right: 15px; *right:0; top: 16px; font-size:0; line-height: initial;} .layui-layer-setwin{position:absolute; right: 15px; top: 16px; font-size:0; line-height: initial;}
.layui-layer-setwin span{position:relative; width: 16px; height: 16px; line-height: 18px; margin-left: 10px; text-align: center; font-size: 16px; cursor: pointer; color: #000; _overflow: hidden; box-sizing: border-box;} .layui-layer-setwin span{position:relative; width: 16px; height: 16px; line-height: 18px; margin-left: 10px; text-align: center; font-size: 16px; cursor: pointer; color: #000; _overflow: hidden; box-sizing: border-box;}
.layui-layer-setwin .layui-layer-min:before{content: ''; position: absolute; width: 12px; border-bottom: 1px solid #2E2D3C; left: 50%; top: 50%; margin: -0.5px 0 0 -6px; cursor: pointer; _overflow:hidden;} .layui-layer-setwin .layui-layer-min:before{content: ''; position: absolute; width: 12px; border-bottom: 1px solid #2E2D3C; left: 50%; top: 50%; margin: -0.5px 0 0 -6px; cursor: pointer; _overflow:hidden;}
.layui-layer-setwin .layui-layer-min:hover:before{background-color: #2D93CA} .layui-layer-setwin .layui-layer-min:hover:before{background-color: #2D93CA}
@ -134,7 +144,7 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
.layui-layer-setwin .layui-layer-maxmin:after{z-index: 0; margin: -5px 0 0 -1px;} .layui-layer-setwin .layui-layer-maxmin:after{z-index: 0; margin: -5px 0 0 -1px;}
.layui-layer-setwin .layui-layer-close{cursor: pointer;} .layui-layer-setwin .layui-layer-close{cursor: pointer;}
.layui-layer-setwin .layui-layer-close:hover{opacity:0.7;} .layui-layer-setwin .layui-layer-close:hover{opacity:0.7;}
.layui-layer-setwin .layui-layer-close2{position:absolute; right: -28px; top: -28px; color: #fff; background-color: #787878; padding: 3px; border: 3px solid; width: 28px; height: 28px; font-size: 16px; font-weight: bolder; border-radius: 50%; margin-left: 0; *right:-18px; _display:none;} .layui-layer-setwin .layui-layer-close2{position:absolute; right: -28px; top: -28px; color: #fff; background-color: #787878; padding: 3px; border: 3px solid; width: 28px; height: 28px; font-size: 16px; font-weight: bolder; border-radius: 50%; margin-left: 0;}
.layui-layer-setwin .layui-layer-close2:hover{opacity: unset; background-color: #3888f6;} .layui-layer-setwin .layui-layer-close2:hover{opacity: unset; background-color: #3888f6;}
/* 按钮栏 */ /* 按钮栏 */
@ -184,7 +194,7 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
.layui-layer-tips{background: none; box-shadow:none; border:none;} .layui-layer-tips{background: none; box-shadow:none; border:none;}
.layui-layer-tips .layui-layer-content{position: relative; line-height: 22px; min-width: 12px; padding: 8px 15px; font-size: 12px; _float:left; border-radius: 2px; box-shadow: 1px 1px 3px rgba(0,0,0,.2); background-color: #000; color: #fff;} .layui-layer-tips .layui-layer-content{position: relative; line-height: 22px; min-width: 12px; padding: 8px 15px; font-size: 12px; _float:left; border-radius: 2px; box-shadow: 1px 1px 3px rgba(0,0,0,.2); background-color: #000; color: #fff;}
.layui-layer-tips .layui-layer-close{right:-2px; top:-1px;} .layui-layer-tips .layui-layer-close{right:-2px; top:-1px;}
.layui-layer-tips i.layui-layer-TipsG{ position:absolute; width:0; height:0; border-width:8px; border-color:transparent; border-style:dashed; *overflow:hidden;} .layui-layer-tips i.layui-layer-TipsG{ position:absolute; width:0; height:0; border-width:8px; border-color:transparent; border-style:dashed;}
.layui-layer-tips i.layui-layer-TipsT, .layui-layer-tips i.layui-layer-TipsB{left:5px; border-right-style:solid; border-right-color: #000;} .layui-layer-tips i.layui-layer-TipsT, .layui-layer-tips i.layui-layer-TipsB{left:5px; border-right-style:solid; border-right-color: #000;}
.layui-layer-tips i.layui-layer-TipsT{bottom:-8px;} .layui-layer-tips i.layui-layer-TipsT{bottom:-8px;}
.layui-layer-tips i.layui-layer-TipsB{top:-8px;} .layui-layer-tips i.layui-layer-TipsB{top:-8px;}
@ -220,18 +230,16 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
/** /**
* layer 拓展层
@Name: layer拓展样式
*/ */
/* prompt模式 */ /* prompt */
.layui-layer-prompt .layui-layer-input{display: block; width: 260px; height: 36px; margin: 0 auto; line-height: 30px; padding-left: 10px; border: 1px solid #e6e6e6; color: #333;} .layui-layer-prompt .layui-layer-input{display: block; width: 260px; height: 36px; margin: 0 auto; line-height: 30px; padding-left: 10px; border: 1px solid #e6e6e6; color: #333;}
.layui-layer-prompt textarea.layui-layer-input{width: 300px; height: 100px; line-height: 20px; padding: 6px 10px;} .layui-layer-prompt textarea.layui-layer-input{width: 300px; height: 100px; line-height: 20px; padding: 6px 10px;}
.layui-layer-prompt .layui-layer-content{padding: 16px;} .layui-layer-prompt .layui-layer-content{padding: 16px;}
.layui-layer-prompt .layui-layer-btn{padding-top: 0;} .layui-layer-prompt .layui-layer-btn{padding-top: 0;}
/* tab模式 */ /* tab */
.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4);} .layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4);}
.layui-layer-tab .layui-layer-title{padding-left:0; overflow: visible;} .layui-layer-tab .layui-layer-title{padding-left:0; overflow: visible;}
.layui-layer-tab .layui-layer-title span{position:relative; display: inline-block; vertical-align: top; border-left: 1px solid transparent; border-right: 1px solid transparent; min-width:80px; max-width: 300px; padding:0 16px; text-align:center; cursor:default; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; cursor: pointer;} .layui-layer-tab .layui-layer-title span{position:relative; display: inline-block; vertical-align: top; border-left: 1px solid transparent; border-right: 1px solid transparent; min-width:80px; max-width: 300px; padding:0 16px; text-align:center; cursor:default; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; cursor: pointer;}
@ -244,7 +252,7 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
/* photos */ /* photos */
.layui-layer-photos{background: none; box-shadow: none;} .layui-layer-photos{background: none; box-shadow: none;}
.layui-layer-photos .layui-layer-content{overflow: visible; text-align: center;} .layui-layer-photos .layui-layer-content{overflow: visible; text-align: center;}
.layui-layer-photos .layer-layer-photos-main img{position: relative; width:100%; display: inline-block; *display:inline; *zoom:1; vertical-align:top;} .layui-layer-photos .layer-layer-photos-main img{position: relative; width:100%; display: inline-block; vertical-align:top;}
.layui-layer-photos-prev, .layui-layer-photos-prev,
.layui-layer-photos-next{position: fixed; top: 50%; width: 52px; height: 52px; line-height: 52px; margin-top: -26px; cursor: pointer; font-size: 52px; color: #717171;} .layui-layer-photos-next{position: fixed; top: 50%; width: 52px; height: 52px; line-height: 52px; margin-top: -26px; cursor: pointer; font-size: 52px; color: #717171;}
.layui-layer-photos-prev{left: 32px;} .layui-layer-photos-prev{left: 32px;}
@ -252,8 +260,8 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
.layui-layer-photos-prev:hover, .layui-layer-photos-prev:hover,
.layui-layer-photos-next:hover{color: #959595;} .layui-layer-photos-next:hover{color: #959595;}
.layui-layer-photos-toolbar{position: fixed; left: 0; right: 0; bottom: 0; width: 100%; height: 52px; line-height: 52px; background-color: #000\9; filter: Alpha(opacity=60); background-color: rgba(0,0,0,.32); color: #fff; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; font-size:0;} .layui-layer-photos-toolbar{position: fixed; left: 0; right: 0; bottom: 0; width: 100%; height: 52px; line-height: 52px; background-color: rgba(0,0,0,.32); color: #fff; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; font-size:0;}
.layui-layer-photos-toolbar > *{display:inline-block; vertical-align: top; padding: 0 16px; font-size: 12px; color: #fff; *display:inline; *zoom: 1;} .layui-layer-photos-toolbar > *{display:inline-block; vertical-align: top; padding: 0 16px; font-size: 12px; color: #fff;}
.layui-layer-photos-toolbar *{font-size: 12px;} .layui-layer-photos-toolbar *{font-size: 12px;}
.layui-layer-photos-header{top: 0; bottom: auto;} .layui-layer-photos-header{top: 0; bottom: auto;}
.layui-layer-photos-header > span{cursor: pointer;} .layui-layer-photos-header > span{cursor: pointer;}

View File

@ -28,7 +28,7 @@
// constructor // constructor
var Class = function() { var Class = function() {
this.v = '2.11.0-rc.2'; // 版本号 this.v = '2.11.4'; // 版本号
}; };
// 识别预先可能定义的指定全局对象 // 识别预先可能定义的指定全局对象
@ -156,7 +156,7 @@
} }
}; };
// 或许配置及临时缓存信息 // 获取配置及临时缓存信息
Class.prototype.cache = Object.assign(config, cache); Class.prototype.cache = Object.assign(config, cache);
/** /**
@ -421,7 +421,7 @@
Class.prototype.link = function(href, callback, id) { Class.prototype.link = function(href, callback, id) {
var that = this; var that = this;
var head = document.getElementsByTagName('head')[0]; var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link'); var hasCallback = typeof callback === 'function';
// 若第二个参数为 string 类型,则该参数为 id // 若第二个参数为 string 类型,则该参数为 id
if (typeof callback === 'string') { if (typeof callback === 'string') {
@ -440,26 +440,31 @@
}); });
} }
// 若传入 id ,则取路径 `//` 后面的字符拼接为 id不含.与参数 // 若传入 id ,则取路径 `//` 后面的字符拼接为 id不含.与参数
id = id || href.replace(/^(#|(http(s?)):\/\/|\/\/)|\.|\/|\?.+/g, ''); id = id || href.replace(/^(#|(http(s?)):\/\/|\/\/)|\.|\/|\?.+/g, '');
id = 'layuicss-'+ id; id = 'layuicss-'+ id;
link.href = href + (config.debug ? '?v='+new Date().getTime() : ''); var link = document.getElementById(id);
link.rel = 'stylesheet';
link.id = id;
// 插入节点 // 初始创建节点
if (!document.getElementById(id)) { if (!link) {
link = document.createElement('link');
link.href = href + (config.debug ? '?v='+new Date().getTime() : '');
link.rel = 'stylesheet';
link.id = id;
head.appendChild(link); head.appendChild(link);
} }
// 是否执行回调 // 若加载已完成,则直接执行回调函数
if (typeof callback !== 'function') { if (link.__lay_readyState__ === 'complete') {
hasCallback && callback(link);
return that; return that;
} }
// 初始加载
onNodeLoad(link, function() { onNodeLoad(link, function() {
callback(link); link.__lay_readyState__ = 'complete';
hasCallback && callback(link);
}, function() { }, function() {
error(href + ' load error', 'error'); error(href + ' load error', 'error');
head.removeChild(link); // 移除节点 head.removeChild(link); // 移除节点
@ -521,12 +526,16 @@
var hash = hash || location.hash; var hash = hash || location.hash;
var data = { var data = {
path: [], path: [],
pathname: [],
search: {}, search: {},
hash: (hash.match(/[^#](#.*$)/) || [])[1] || '', hash: (hash.match(/[^#](#.*$)/) || [])[1] || '',
href: '' href: ''
}; };
if (!/^#/.test(hash)) return data; // 禁止非路由规范 // 禁止非 hash 路由规范
if (!/^#/.test(hash)) {
return data;
}
hash = hash.replace(/^#/, ''); hash = hash.replace(/^#/, '');
data.href = hash; data.href = hash;
@ -540,6 +549,7 @@
}() : data.path.push(item); }() : data.path.push(item);
}); });
data.pathname = data.path; // path → pathname, 与 layui.url 一致
return data; return data;
}; };

View File

@ -152,14 +152,14 @@ layui.define(['jquery', 'lay'], function(exports) {
} }
// 渲染 // 渲染
if (typeof settings.render === 'function') { if (typeof that.render === 'function') {
component.cache.id[options.id] = null; // 记录所有实例 id用于批量操作如 resize component.cache.id[options.id] = null; // 记录所有实例 id用于批量操作如 resize
elem.attr(MOD_ID, options.id); // 目标元素已渲染过的标记 elem.attr(MOD_ID, options.id); // 目标元素已渲染过的标记
that.render(rerender); // 渲染核心 that.render(rerender); // 渲染核心
} }
// 事件 // 事件
typeof settings.events === 'function' && that.events(); typeof that.events === 'function' && that.events();
}; };
// 组件必传项 // 组件必传项

View File

@ -567,7 +567,29 @@ layui.define(['jquery', 'laytpl', 'lay', 'util'], function(exports) {
} }
that.remove(); that.remove();
}, {passive: false}); }, lay.passiveSupported ? { passive: false} : false);
// onClickOutside 检测 iframe
_WIN.on('blur', function(e){
if(!dropdown.thisId) return;
var that = thisModule.getThis(dropdown.thisId)
if(!that) return;
if(!that.config.elem.data(MOD_INDEX_OPENED)) return;
setTimeout(function(){
if(document.activeElement && document.activeElement.tagName === 'IFRAME'
&& that.mainElem && that.mainElem[0]
&& that.mainElem[0].contains && !that.mainElem[0].contains(document.activeElement)
){
// 点击 dropdown 外部时的回调
if(typeof that.config.onClickOutside === 'function'){
var shouldClose = that.config.onClickOutside(e.originalEvent);
if(shouldClose === false) return;
}
that.remove();
}
}, 0);
})
// 基础菜单的静态元素事件 // 基础菜单的静态元素事件
var ELEM_LI = '.layui-menu:not(.layui-dropdown-menu) li'; var ELEM_LI = '.layui-menu:not(.layui-dropdown-menu) li';

View File

@ -404,28 +404,51 @@ layui.define('jquery', function(exports) {
} }
// 折叠面板 // 折叠面板
,collapse: function(){ ,collapse: function() {
var othis = $(this); var othis = $(this);
var icon = othis.find('.layui-colla-icon'); var wrapper = othis.closest('.layui-collapse');
var elemCont = othis.siblings('.layui-colla-content'); var filter = wrapper.attr('lay-filter');
var parents = othis.parents('.layui-collapse').eq(0);
var filter = parents.attr('lay-filter');
var isNone = elemCont.css('display') === 'none';
// 是否手风琴 var ANIM_MS = 200; // 动画过渡毫秒数
if(typeof parents.attr('lay-accordion') === 'string'){ var CLASS_ITEM = '.layui-colla-item';
var show = parents.children('.layui-colla-item').children('.'+SHOW); var CLASS_CONTENT = '.layui-colla-content';
show.siblings('.layui-colla-title').children('.layui-colla-icon').html('&#xe602;');
show.removeClass(SHOW); var thisItemElem = othis.parent(CLASS_ITEM);
var thisContentElem = othis.siblings(CLASS_CONTENT);
var isNone = thisContentElem.css('display') === 'none';
var isAccordion = typeof wrapper.attr('lay-accordion') === 'string';
// 动画执行完成后的操作
var complete = function() {
$(this).css('display', ''); // 剔除动画生成的 style display以适配外部样式的状态重置
};
// 是否正处于动画中的状态
if (thisContentElem.is(':animated')) return;
// 展开或收缩
if (isNone) {
// 先执行 slideDown 动画,再标注展开状态样式,避免元素 `block` 状态导致动画无效
thisContentElem.slideDown(ANIM_MS, complete);
thisItemElem.addClass(SHOW);
} else {
// 先取消展开状态样式,再将元素临时显示,避免 `none` 状态导致 slideUp 动画无效
thisItemElem.removeClass(SHOW);
thisContentElem.show().slideUp(ANIM_MS, complete);
} }
elemCont[isNone ? 'addClass' : 'removeClass'](SHOW); // 是否开启手风琴
icon.html(isNone ? '&#xe61a;' : '&#xe602;'); if (isAccordion) {
var itemSiblings = thisItemElem.siblings('.'+ SHOW);
itemSiblings.removeClass(SHOW);
itemSiblings.children(CLASS_CONTENT).show().slideUp(ANIM_MS, complete);
}
// 事件
layui.event.call(this, MOD_NAME, 'collapse('+ filter +')', { layui.event.call(this, MOD_NAME, 'collapse('+ filter +')', {
title: othis title: othis,
,content: elemCont content: thisContentElem,
,show: isNone show: isNone
}); });
} }
}; };
@ -617,27 +640,32 @@ layui.define('jquery', function(exports) {
}); });
} }
//折叠面板 // 折叠面板
,collapse: function(elem){ ,collapse: function(elem) {
var ELEM = 'layui-collapse'; var ELEM = 'layui-collapse';
var targetElem = elem || $('.' + ELEM + elemFilter); var targetElem = elem || $('.' + ELEM + elemFilter);
targetElem.each(function(){ targetElem.each(function() {
var elemItem = $(this).find('.layui-colla-item') var elemItem = $(this).find('.layui-colla-item');
elemItem.each(function(){ elemItem.each(function() {
var othis = $(this) var othis = $(this)
,elemTitle = othis.find('.layui-colla-title') var elemTitle = othis.find('.layui-colla-title');
,elemCont = othis.find('.layui-colla-content') var elemCont = othis.find('.layui-colla-content');
,isNone = elemCont.css('display') === 'none'; var isNone = elemCont.css('display') === 'none';
//初始状态 // 初始状态
elemTitle.find('.layui-colla-icon').remove(); elemTitle.find('.layui-colla-icon').remove();
elemTitle.append('<i class="layui-icon layui-colla-icon">'+ (isNone ? '&#xe602;' : '&#xe61a;') +'</i>'); elemTitle.append('<i class="layui-icon layui-icon-right layui-colla-icon"></i>');
othis[isNone ? 'removeClass' : 'addClass'](SHOW);
//点击标题 // 兼容旧版( < 2.11.3
if (elemCont.hasClass(SHOW)) {
elemCont.removeClass(SHOW);
}
// 点击标题
elemTitle.off('click', call.collapse).on('click', call.collapse); elemTitle.off('click', call.collapse).on('click', call.collapse);
}); });
}); });
} }
}; };

View File

@ -10,7 +10,6 @@ layui.define(['lay', 'layer', 'util'], function(exports){
var util = layui.util; var util = layui.util;
var hint = layui.hint(); var hint = layui.hint();
var device = layui.device(); var device = layui.device();
var needCheckboxFallback = lay.ie && parseFloat(lay.ie) === 8;
var MOD_NAME = 'form'; var MOD_NAME = 'form';
var ELEM = '.layui-form'; var ELEM = '.layui-form';
@ -21,6 +20,11 @@ layui.define(['lay', 'layer', 'util'], function(exports){
var OUT_OF_RANGE = 'layui-input-number-out-of-range'; var OUT_OF_RANGE = 'layui-input-number-out-of-range';
var BAD_INPUT = 'layui-input-number-invalid'; var BAD_INPUT = 'layui-input-number-invalid';
// ie8 中可以获取到 input 元素的 'indeterminate' 属性描述符,但重新定义 getter/setter 无效,无报错
// AppleWebKit/537.36 无法获取 input 元素任意属性的属性描述符(包括lookupGetter),但可以重新定义 getter/setter
var needCheckboxFallback = (lay.ie && parseFloat(lay.ie) === 8)
|| typeof Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'checked') === 'undefined'
var Form = function(){ var Form = function(){
this.config = { this.config = {
// 内置的验证规则 // 内置的验证规则
@ -554,7 +558,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
hideDown(); hideDown();
initValue && input.val(initValue); initValue && input.val(initValue);
}, },
{ignore: title} {ignore: title, detectIframe: true, capture: false}
); );
}; };
@ -563,7 +567,10 @@ layui.define(['lay', 'layer', 'util'], function(exports){
title.parent().removeClass(CLASS+'ed ' + CLASS+'up'); title.parent().removeClass(CLASS+'ed ' + CLASS+'up');
input.blur(); input.blur();
isCreatable && dl.children('.' + CREATE_OPTION).remove(); isCreatable && dl.children('.' + CREATE_OPTION).remove();
removeClickOutsideEvent && removeClickOutsideEvent(); if(typeof removeClickOutsideEvent === 'function'){
removeClickOutsideEvent();
removeClickOutsideEvent = null;
}
if(isAppendTo){ if(isAppendTo){
reElem.detach(); reElem.detach();
$(window).off('resize.lay_select_resize'); $(window).off('resize.lay_select_resize');
@ -576,7 +583,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
// 未查询到相关值 // 未查询到相关值
if(none){ if(none){
initValue = $(select[0].options[selectedIndex]).html(); // 重新获得初始选中值 initValue = $(select[0].options[selectedIndex]).prop('text'); // 重新获得初始选中值
// 如果是第一项,且文本值等于 placeholder则清空初始值 // 如果是第一项,且文本值等于 placeholder则清空初始值
if(selectedIndex === 0 && initValue === input.attr('placeholder')){ if(selectedIndex === 0 && initValue === input.attr('placeholder')){
@ -747,10 +754,10 @@ layui.define(['lay', 'layer', 'util'], function(exports){
}else{ }else{
var createOptionElem = dl.children('.' + CREATE_OPTION); var createOptionElem = dl.children('.' + CREATE_OPTION);
if(createOptionElem[0]){ if(createOptionElem[0]){
createOptionElem.attr('lay-value', value).html(util.escape(value)); createOptionElem.attr('lay-value', value).text(value);
}else{ }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 firstOptionELem = dl.children().eq(0);
var hasTips = firstOptionELem.hasClass('layui-select-tips'); var hasTips = firstOptionELem.hasClass('layui-select-tips');
firstOptionELem[hasTips ? 'after' : 'before'](ddElem); firstOptionELem[hasTips ? 'after' : 'before'](ddElem);
@ -782,7 +789,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
input.on('input propertychange', layui.debounce(search, 50)).on('blur', function(e){ input.on('input propertychange', layui.debounce(search, 50)).on('blur', function(e){
var selectedIndex = select[0].selectedIndex; var selectedIndex = select[0].selectedIndex;
initValue = $(select[0].options[selectedIndex]).text(); // 重新获得初始选中值 initValue = $(select[0].options[selectedIndex]).prop('text'); // 重新获得初始选中值
// 如果是第一项,且文本值等于 placeholder则清空初始值 // 如果是第一项,且文本值等于 placeholder则清空初始值
if(selectedIndex === 0 && initValue === input.attr('placeholder')){ if(selectedIndex === 0 && initValue === input.attr('placeholder')){
@ -804,6 +811,17 @@ layui.define(['lay', 'layer', 'util'], function(exports){
if(othis.hasClass(DISABLED)) return false; if(othis.hasClass(DISABLED)) return false;
// 将新增的 option 元素添加到末尾
if(isCreatable && othis.hasClass(CREATE_OPTION)){
var optionElem = $('<option>').text(othis.text());
var displayValue = optionElem.prop('text');
value = displayValue;
optionElem.attr('value', displayValue);
select.append(optionElem);
othis.removeClass(CREATE_OPTION).attr('lay-value', displayValue).text(displayValue);
dl.append(othis);
}
if(othis.hasClass('layui-select-tips')){ if(othis.hasClass('layui-select-tips')){
input.val(''); input.val('');
} else { } else {
@ -811,13 +829,6 @@ layui.define(['lay', 'layer', 'util'], function(exports){
othis.addClass(THIS); othis.addClass(THIS);
} }
// 将新增的 option 元素添加到末尾
if(isCreatable && othis.hasClass(CREATE_OPTION)){
dl.append(othis.removeClass(CREATE_OPTION));
var optionElem = $('<option>').attr('value', value).text(othis.text());
select.append(optionElem);
}
othis.siblings().removeClass(THIS); othis.siblings().removeClass(THIS);
select.val(value).removeClass('layui-form-danger'); select.val(value).removeClass('layui-form-danger');
@ -855,7 +866,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
}; };
// 初始渲染 select 组件选项 // 初始渲染 select 组件选项
selects.each(function(index, select){ selects.each(function(index, select) {
var othis = $(this); var othis = $(this);
var hasRender = othis.next('.'+CLASS); var hasRender = othis.next('.'+CLASS);
var disabled = this.disabled; var disabled = this.disabled;
@ -863,67 +874,114 @@ layui.define(['lay', 'layer', 'util'], function(exports){
var selected = $(select.options[select.selectedIndex]); // 获取当前选中项 var selected = $(select.options[select.selectedIndex]); // 获取当前选中项
var optionsFirst = select.options[0]; var optionsFirst = select.options[0];
if (othis.closest('[lay-ignore]').length) return othis.show(); // 为忽略渲染的 select 元素保持原生显示状态
if (othis.closest('[lay-ignore]').length) {
return othis.show();
}
var isSearch = typeof othis.attr('lay-search') === 'string' var isSearch = typeof othis.attr('lay-search') === 'string';
var isCreatable = typeof othis.attr('lay-creatable') === 'string' && isSearch var isCreatable = typeof othis.attr('lay-creatable') === 'string' && isSearch;
var isAppendTo = typeof othis.attr('lay-append-to') === 'string' var isAppendTo = typeof othis.attr('lay-append-to') === 'string';
var placeholder = optionsFirst var placeholder = optionsFirst
? (optionsFirst.value ? TIPS : (optionsFirst.innerHTML || TIPS)) ? (optionsFirst.value ? TIPS : (optionsFirst.text || TIPS))
: TIPS; : TIPS;
// 替代元素 // 用于替代 select 的外层容器
var reElem = $(['<div class="'+ (isSearch ? '' : 'layui-unselect ') + CLASS var selectWrapper = (function() {
,(disabled ? ' layui-select-disabled' : '') + '"></div>'].join('')); var elem = $('<div class="'+ CLASS +'"></div>');
if (!isSearch) {
elem.addClass('layui-unselect');
}
if (disabled) {
elem.addClass('layui-select-disabled');
}
return elem;
})();
var triggerElem = $([ var inputElem = (function() {
'<div class="'+ TITLE +'">' var elem = $('<input type="text" class="layui-input">');
,('<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 contentElem = $(['<dl class="layui-anim layui-anim-upbit'+ (othis.find('optgroup')[0] ? ' layui-select-group' : '') +'">' // 设置占位符和默认值
,function(options){ elem.prop('placeholder', placeholder);
elem.val(value ? selected.prop('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 = []; var arr = [];
layui.each(options, function(index, item){ layui.each(othis.find('optgroup,option'), function(index, item) {
var tagName = item.tagName.toLowerCase(); var tagName = item.tagName.toLowerCase();
var dd = $('<dd lay-value=""></dd>');
if(index === 0 && !item.value && tagName !== 'optgroup'){ if (index === 0 && !item.value && tagName !== 'optgroup') {
arr.push('<dd lay-value="" class="layui-select-tips">'+ $.trim(item.innerHTML || TIPS) +'</dd>'); dd.addClass('layui-select-tips');
} else if(tagName === 'optgroup'){ dd.text(item.text || TIPS);
arr.push('<dt>'+ item.label +'</dt>'); arr.push(dd.prop('outerHTML'));
} else if(tagName === 'optgroup') {
var dt = $('<dt></dt>');
dt.text(item.label);
arr.push(dt.prop('outerHTML'));
} else { } 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(item.text);
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(''); return arr.join('');
}(othis.find('*')) +'</dl>' }();
].join('')); elem.html(content);
return elem;
})();
// 如果已经渲染则Rerender // 如果已经渲染,则 Rerender
if(hasRender[0]){ if (hasRender[0]) {
if(isAppendTo){ if (isAppendTo) {
var panelWrapElem = hasRender.data(PANEL_ELEM_DATA); var panelWrapElem = hasRender.data(PANEL_ELEM_DATA);
panelWrapElem && panelWrapElem.remove(); panelWrapElem && panelWrapElem.remove();
} }
hasRender.remove(); hasRender.remove();
} }
if(isAppendTo){ if (isAppendTo) {
reElem.append(triggerElem); selectWrapper.append(titleElem);
othis.after(reElem); othis.after(selectWrapper);
var contentWrapElem = $('<div class="'+ CLASS + ' ' + PANEL_WRAP +'"></div>').append(contentElem); var contentWrapElem = $('<div class="'+ CLASS + ' ' + PANEL_WRAP +'"></div>').append(contentElem);
reElem.data(PANEL_ELEM_DATA, contentWrapElem); // 将面板元素对象记录在触发元素 data 中,重新渲染时需要清理旧面板元素 selectWrapper.data(PANEL_ELEM_DATA, contentWrapElem); // 将面板元素对象记录在触发元素 data 中,重新渲染时需要清理旧面板元素
events.call(this, contentWrapElem, triggerElem, disabled, isSearch, isCreatable, isAppendTo); events.call(this, contentWrapElem, titleElem, disabled, isSearch, isCreatable, isAppendTo);
}else{ } else {
reElem.append(triggerElem).append(contentElem); selectWrapper.append(titleElem).append(contentElem);
othis.after(reElem); othis.after(selectWrapper);
events.call(this, reElem, triggerElem, disabled, isSearch, isCreatable, isAppendTo); events.call(this, selectWrapper, titleElem, disabled, isSearch, isCreatable, isAppendTo);
} }
}); });
} }
@ -1469,5 +1527,3 @@ layui.define(['lay', 'layer', 'util'], function(exports){
exports(MOD_NAME, form); exports(MOD_NAME, form);
}); });

View File

@ -551,11 +551,12 @@
/** /**
* 基于 touch 事件的触摸滑动 * 基于 touch 事件的触摸滑动
* @param {string | HTMLElement | JQuery} elem - HTML 元素 * @param {string | HTMLElement | JQuery} elem - HTML 元素
* @param {{onTouchStart?: touchSwipeCallback, onTouchMove?: touchSwipeCallback, onTouchEnd?: touchSwipeCallback}} opts - 配置项 * @param {{onTouchStart?: touchSwipeCallback; onTouchMove?: touchSwipeCallback; onTouchEnd?: touchSwipeCallback; preventDefault?: boolean}} opts - 配置项
*/ */
lay.touchSwipe = function(elem, opts){ lay.touchSwipe = function(elem, opts){
var options = opts var options = opts
var targetElem = lay(elem)[0]; var targetElem = lay(elem)[0];
var preventDefault = 'preventDefault' in options ? options.preventDefault : true;
if(!targetElem || !lay.touchEventsSupported()) return; if(!targetElem || !lay.touchEventsSupported()) return;
@ -582,7 +583,9 @@
} }
var onMove = function(e){ var onMove = function(e){
e.preventDefault(); if(preventDefault){
e.preventDefault();
}
state.pointerEnd.x = e.touches[0].clientX; state.pointerEnd.x = e.touches[0].clientX;
state.pointerEnd.y = e.touches[0].clientY; state.pointerEnd.y = e.touches[0].clientY;
state.distanceX = state.pointerStart.x - state.pointerEnd.x; state.distanceX = state.pointerStart.x - state.pointerEnd.x;
@ -680,15 +683,16 @@
}(); }();
/** /**
* 监听指定元素外部的点击 * 绑定指定元素外部的点击事件
* @param {HTMLElement} target - 被监听的元素 * @param {HTMLElement} target - 响应事件的元素
* @param {(e: Event) => void} handler - 事件触发时执行的函数 * @param {(e: Event) => void} handler - 事件触发时执行的函数
* @param {object} [options] - 选项 * @param {object} [options] - 选项
* @param {string} [options.event="pointerdown"] - 监听的事件类型 * @param {string} [options.event="pointerdown"] - 事件类型
* @param {HTMLElement | Window} [options.scope=document] - 监听范围 * @param {HTMLElement | Window} [options.scope=document] - 事件范围
* @param {Array<HTMLElement | string>} [options.ignore] - 忽略监听的元素或选择器字符串 * @param {Array<HTMLElement | string>} [options.ignore] - 忽略触发事件的元素或选择器字符串
* @param {boolean} [options.capture=true] - 对内部事件侦听器使用捕获阶段 * @param {boolean} [options.capture=true] - 对内部事件 listener 使用捕获阶段
* @returns {() => void} - 返回一个停止事件监听的函数 * @param {boolean} [options.detectIframe] - 是否检测 iframe
* @returns {() => void} - 返回一个停止事件响应的函数
*/ */
lay.onClickOutside = function(target, handler, options){ lay.onClickOutside = function(target, handler, options){
options = options || {}; options = options || {};
@ -696,6 +700,7 @@
var scopeTarget = options.scope || document; var scopeTarget = options.scope || document;
var ignore = options.ignore || []; var ignore = options.ignore || [];
var useCapture = 'capture' in options ? options.capture : true; var useCapture = 'capture' in options ? options.capture : true;
var detectIframe = options.detectIframe;
var listener = function(event){ var listener = function(event){
var el = target; var el = target;
@ -764,13 +769,31 @@
} }
} }
return bindEventListener( var cleanup = [
scopeTarget, bindEventListener(
eventType, scopeTarget,
listener, eventType,
lay.passiveSupported ? { passive: true, capture: useCapture } : useCapture listener,
); lay.passiveSupported ? { passive: true, capture: useCapture } : useCapture
} ),
detectIframe && bindEventListener(window, 'blur', function(event){
setTimeout(function(){
if(document.activeElement && document.activeElement.tagName === 'IFRAME'
&& target.contains && !target.contains(document.activeElement)
){
handler(event);
}
}, 0);
})
];
return function(){
for(var i=0; i < cleanup.length; i++){
cleanup[i] && cleanup[i]();
}
cleanup = null;
}
};
var hasOwnProperty = Object.prototype.hasOwnProperty; var hasOwnProperty = Object.prototype.hasOwnProperty;
lay.hasOwn = function(obj, prop){ lay.hasOwn = function(obj, prop){

View File

@ -12,6 +12,7 @@
var thisModule = function() { var thisModule = function() {
var that = this; var that = this;
var options = that.config; var options = that.config;
return { return {
config: options, config: options,
@ -76,9 +77,9 @@
var vars = { var vars = {
// 字符转义 // 字符转义
escape: function(html) { escape: function(html) {
var exp = /[<"'>]|&(?=#[a-zA-Z0-9]+)/g; var exp = /[<"'>]|&(?=#?[a-zA-Z0-9]+)/g;
if (html === undefined || html === null) return ''; if (html === undefined || html === null) return '';
html = ''+ html; html += '';
if (!exp.test(html)) return html; if (!exp.test(html)) return html;
return html.replace(exp, function(str) { return html.replace(exp, function(str) {
return '&#'+ str.charCodeAt(0) + ';'; return '&#'+ str.charCodeAt(0) + ';';
@ -88,6 +89,12 @@
// 组件工具类方法 // 组件工具类方法
var tools = { var tools = {
/**
* 创建动态正则表达式
* @param {string} str - 表达式字符
* @param {string} mod - 修饰符
* @returns {RegExp} - 正则表达式
*/
regex: function(str, mod) { regex: function(str, mod) {
return new RegExp(str, mod || 'g'); return new RegExp(str, mod || 'g');
}, },
@ -102,14 +109,17 @@
error: function(e, opts, error) { error: function(e, opts, error) {
opts = opts || {}; opts = opts || {};
opts = Object.assign({ opts = Object.assign({
debug: '', errorContext: ''
message: 'Laytpl '+ (opts.type || '') +'Error: ' + e
}, opts); }, opts);
// 向控制台输出错误信息 // 向控制台输出错误信息
typeof console === 'object' && console.error(opts.message, '\n', opts.debug, '\n', opts); var message = 'Laytpl '+ (opts.type || '') +'Error: ' + e;
var errorContext = opts.errorContext;
delete opts.errorContext;
typeof console === 'object' && console.error(message, '\n', errorContext, '\n', opts);
typeof error === 'function' && error(opts); // 执行错误回调 typeof error === 'function' && error(opts); // 执行错误回调
return opts.message; // 向视图返回错误提示 return message; // 向视图返回错误提示
} }
}; };
@ -173,7 +183,7 @@
} catch(e) { } catch(e) {
template = template || options.template; template = template || options.template;
return tools.error(e, { return tools.error(e, {
debug: that.checkErrorArea(template, data), errorContext: that.extractErrorContext(template, data),
template: template, template: template,
type: 'Render' type: 'Render'
}, options.error); }, options.error);
@ -196,12 +206,11 @@
Class.prototype.compile = function(template) { Class.prototype.compile = function(template) {
var that = this; var that = this;
var options = that.config; var options = that.config;
var source = template;
var openDelimiter = options.open; var openDelimiter = options.open;
var closeDelimiter = options.close; var closeDelimiter = options.close;
var condense = options.condense; var condense = options.condense;
var regex = tools.regex; var regex = tools.regex;
const placeholder = '\u2028'; // Unicode 行分隔符 var placeholder = '\u2028'; // Unicode 行分隔符
// console.log('compile'); // console.log('compile');
@ -339,9 +348,17 @@
return tpl; return tpl;
}; };
// 创建模板编译器 /**
var createCompiler = that.createCompiler = function(template) { * 创建模板编译器
var codeBuilder = [ * 请注意: 开发者在使用模板语法时需确保模板中的 JS 语句不来自于页面用户输入
* 即模板中的 JS 语句必须在页面开发者自身的可控范围内否则请避免使用该模板解析
*/
var createCompiler = that.createCompiler = function(template, builder) {
builder = builder || createBuilder(template);
return new Function('laytpl', 'return '+ builder)(that.vars);
};
var createBuilder = that.createBuilder = function(template, builder) {
builder = builder || [
'function(d){', 'function(d){',
'"use strict";', '"use strict";',
'var __laytpl__="",'+ 'var __laytpl__="",'+
@ -359,13 +376,8 @@
// 'return __laytpl__.join("");', // 'return __laytpl__.join("");',
'};' '};'
].join('\n'); ].join('\n');
// console.log(codeBuilder); // console.log(builder);
return builder;
/**
* 请注意: 开发者在使用模板语法时需确保模板中的 JS 语句不来自于页面用户输入
* 即模板中的 JS 语句必须在页面开发者自身的可控范围内否则请避免使用该模板解析
*/
return new Function('laytpl', 'return '+ codeBuilder)(that.vars);
}; };
try { try {
@ -374,8 +386,8 @@
delete that.compilerCache; delete that.compilerCache;
return function() { return function() {
return tools.error(e, { return tools.error(e, {
debug: that.checkErrorArea(source), errorContext: that.extractErrorContext(template),
template: source, template: template,
type: 'Compile' type: 'Compile'
}, options.error); }, options.error);
}; };
@ -383,61 +395,82 @@
}; };
/** /**
* 校验出错区域 * 获取模板出错行上下文
* @param {string} source - 原始模板 * @param {string} template - 原始模板
* @param {Object} data - 数据 * @param {Object} data - 数据
* @returns {string} 出错区域的模板碎片 * @returns {string}
*/ */
Class.prototype.checkErrorArea = function(source, data) { Class.prototype.extractErrorContext = function(template, data) {
var that = this; var that = this;
var srcs = source.split(/\n/g);
var validLine = -1; // 有效行
// 逐行查找 // 给模板每行开头添加行号标记
var i = 0; var lineNum = 1; // 行号
var str = ''; var templateArr = template.split(/\r?\n/g);
var len = srcs.length;
for (; i < len; i++) {
str += srcs[i];
try {
data
? that.createCompiler(str)(data)
: new Function('"use strict";_laytpl__="'+ that.parse(str) +'";');
validLine = i;
} catch(e) {
continue;
}
}
// 呈现模板出错大致区域 template = template.replace(/(?=^)/gm, function() {
var errorArea = function(errLine) { return '/*LINE:'+ (lineNum++) +'*/';
var arr = []; });
var addLine = 3; // 错误行上下延伸的行数
var i = 0;
var len = srcs.length;
if (errLine < 0) errLine = 0; var builder = that.createBuilder(template);
if (errLine > len - 1) errLine = len - 1; var builderArr = builder.split(/\r?\n/);
var sourceURL = 'laytpl.builder.map';
i = errLine - addLine; // 模板出错行上下文
if (i < 0) i = 0; var errorContext = function(errLineNum) {
errLineNum = parseInt(errLineNum) - 1;
for (; i < len; i++) { var arr = [''];
arr.push((i == errLine ? '? ' : ' ') +(i + 1)+ '| '+ srcs[i]); var contextLines = 3; // 错误行上下延伸的行数
if (i >= errLine + addLine) break; var start = Math.max(0, errLineNum - contextLines);
var end = Math.min(templateArr.length, errLineNum + contextLines);
for (; start <= end; start++) {
arr.push(
(start == errLineNum ? '? ' : ' ') +
((start + 1) + '| ') +
templateArr[start]
);
} }
return '\n'+ arr.join('\n'); return arr.join('\n') + '\n';
}; };
return errorArea(validLine + 1); // 有效行的下一行即为出错行 try {
builder += ('\n//# sourceURL='+ sourceURL); // 添加映射
var compiler = that.createCompiler(template, builder);
if (data) compiler(data);
} catch(e) {
// 提取堆栈报错行号
var stackLineNumRegxp = tools.regex(sourceURL.replace(/\./g, '\\.')+':(\\d+)', 'i');
var stackLineNum = (e.stack.match(stackLineNumRegxp) || [])[1] || 0;
// 提取模板实际行号
var extractErrLineNum = function(stackLineNum, isRecursion) {
var lineNumRegxp = isRecursion ? /\/\*LINE:(\d+)\*\/[^*]*$/ : /\/\*LINE:(\d+)\*\//;
var errLineNum = String(builderArr[stackLineNum - 1]).match(lineNumRegxp) || [];
errLineNum = errLineNum[1];
// 若当前行未找到行号映射,则递归查找上一行
if (!errLineNum && stackLineNum > 0) {
return extractErrLineNum(stackLineNum - 1, true);
}
return errLineNum;
};
// 此处减去 anonymous 开头占用的 2 行
var errLineNum = extractErrLineNum(stackLineNum - 2);
// 若未找到映射行号,则直接返回 SyntaxError 对象(通过 DevTools 映射源查看模板行号标记)
return errLineNum ? errorContext(errLineNum) : e;
}
}; };
/** /**
* 创建实例 * 创建实例
* @param {string} template - 模板 * @param {string} template - 模板
* @param {Object} options - 选项 * @param {Object} options - 选项
* @returns * @returns {Object}
*/ */
var laytpl = function(template, options) { var laytpl = function(template, options) {
var inst = new Class(template, options); var inst = new Class(template, options);
@ -461,15 +494,15 @@
}; };
// 输出接口 // 输出接口
typeof module === 'object' && typeof exports === 'object' typeof layui === 'object' ? layui.define(function(exports) { // Layui
? module.exports = laytpl // CommonJS exports(MOD_NAME, laytpl);
: ( // 浏览器 }) : (
typeof layui === 'object' ? layui.define(function(exports) { // Layui typeof module === 'object' && typeof exports === 'object'
exports(MOD_NAME, laytpl); ? module.exports = laytpl // CommonJS
}) : ( : (
typeof define === 'function' && define.amd ? define(function() { // RequireJS typeof define === 'function' && define.amd ? define(function() { // RequireJS
return laytpl; return laytpl;
}) : global.laytpl = laytpl // 单独引入 }) : global.laytpl = laytpl // 单独引入
) )
); );
})(this); })(this);

View File

@ -415,7 +415,8 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports) {
return obj; return obj;
}()).html(laytpl(TPL_MAIN, { }()).html(laytpl(TPL_MAIN, {
open: '{{', // 标签符前缀 open: '{{', // 标签符前缀
close: '}}' // 标签符后缀 close: '}}', // 标签符后缀
tagStyle: 'legacy'
}).render({ }).render({
data: options, data: options,
index: that.index //索引 index: that.index //索引

View File

@ -54,7 +54,7 @@ layui.define('component', function(exports) {
// 若 header 选项类型为数组 // 若 header 选项类型为数组
if (layui.type(options.header) === 'array') { if (layui.type(options.header) === 'array') {
if (options.header.length === 0) return; // if (options.header.length === 0) return;
// 给任意元素绑定 tabs 切换功能 // 给任意元素绑定 tabs 切换功能
if (typeof options.header[0] === 'string') { if (typeof options.header[0] === 'string') {
@ -183,6 +183,7 @@ layui.define('component', function(exports) {
var container = that.getContainer(); var container = that.getContainer();
var newHeaderItem = that.renderHeaderItem(opts); var newHeaderItem = that.renderHeaderItem(opts);
var newBodyItem = that.renderBodyItem(opts); var newBodyItem = that.renderBodyItem(opts);
var data = that.data();
// 选项默认值 // 选项默认值
opts = $.extend({ opts = $.extend({
@ -191,7 +192,6 @@ layui.define('component', function(exports) {
// 插入方式 // 插入方式
if (/(before|after)/.test(opts.mode)) { // 在活动标签前后插入 if (/(before|after)/.test(opts.mode)) { // 在活动标签前后插入
var data = that.data();
var hasOwnIndex = opts.hasOwnProperty('index'); var hasOwnIndex = opts.hasOwnProperty('index');
var headerItem = hasOwnIndex ? that.findHeaderItem(opts.index) : data.thisHeaderItem; var headerItem = hasOwnIndex ? that.findHeaderItem(opts.index) : data.thisHeaderItem;
var bodyItem = hasOwnIndex ? that.findBodyItem(opts.index) : data.thisHeaderItem; var bodyItem = hasOwnIndex ? that.findBodyItem(opts.index) : data.thisHeaderItem;
@ -214,8 +214,12 @@ layui.define('component', function(exports) {
} }
// 回调 // 回调
var params = that.data(); typeof opts.done === 'function' && opts.done(
typeof opts.done === 'function' && opts.done(params); $.extend(data, {
headerItem: newHeaderItem,
bodyItem: newBodyItem
})
);
}; };
/** /**
@ -224,21 +228,20 @@ layui.define('component', function(exports) {
* @param {boolean} force - 是否强制删除 * @param {boolean} force - 是否强制删除
*/ */
Class.prototype.close = function(thisHeaderItem, force) { Class.prototype.close = function(thisHeaderItem, force) {
if(!thisHeaderItem || !thisHeaderItem[0]) return; if (!thisHeaderItem || !thisHeaderItem[0]) return;
var that = this; var that = this;
var options = that.config; var options = that.config;
var layid = thisHeaderItem.attr('lay-id');
var index = thisHeaderItem.index(); var index = thisHeaderItem.index();
if (!thisHeaderItem[0]) return;
// 标签是否不可关闭 // 标签是否不可关闭
if (thisHeaderItem.attr('lay-closable') === 'false') { if (thisHeaderItem.attr('lay-closable') === 'false') {
return; return;
} }
// 当前标签相关数据 // 当前标签相关数据
var params = that.data(); var data = that.data();
// 标签关闭前的事件。若非强制关闭,可则根据事件的返回结果决定是否关闭 // 标签关闭前的事件。若非强制关闭,可则根据事件的返回结果决定是否关闭
if (!force) { if (!force) {
@ -246,8 +249,8 @@ layui.define('component', function(exports) {
thisHeaderItem[0], thisHeaderItem[0],
component.CONST.MOD_NAME, component.CONST.MOD_NAME,
'beforeClose('+ options.id +')', 'beforeClose('+ options.id +')',
$.extend(params, { $.extend(data, {
index: thisHeaderItem.index() index: index
}) })
); );
@ -267,20 +270,20 @@ layui.define('component', function(exports) {
} }
// 移除元素 // 移除元素
that.findBodyItem(layid || index).remove();
thisHeaderItem.remove(); thisHeaderItem.remove();
that.findBodyItem(index).remove();
that.roll('auto', index); that.roll('auto', index);
// 获取当前标签相关数据 // 获取当前标签相关数据
var params = that.data(); var data = that.data();
// 标签关闭后的事件 // 标签关闭后的事件
layui.event.call( layui.event.call(
params.thisHeaderItem[0], data.thisHeaderItem[0],
component.CONST.MOD_NAME, component.CONST.MOD_NAME,
'afterClose('+ options.id +')', 'afterClose('+ options.id +')',
params data
); );
}; };
@ -300,14 +303,9 @@ layui.define('component', function(exports) {
index = index === undefined ? data.index : index; index = index === undefined ? data.index : index;
// 将标签头 lay-closable 属性值同步到 body 项 var headerItem = that.findHeaderItem(index);
headers.each(function(i) { var bodyItem = that.findBodyItem(index);
var othis = $(this); var itemIndex = headerItem.index();
var closableAttr = othis.attr('lay-closable');
if (closableAttr) {
bodys.eq(i).attr('lay-closable', closableAttr);
}
});
// 若当前选中标签也允许关闭,则尝试寻找不可关闭的标签并将其选中 // 若当前选中标签也允许关闭,则尝试寻找不可关闭的标签并将其选中
if (data.thisHeaderItem.attr('lay-closable') !== 'false') { if (data.thisHeaderItem.attr('lay-closable') !== 'false') {
@ -319,34 +317,45 @@ layui.define('component', function(exports) {
} else if(prevHeader[0]) { } else if(prevHeader[0]) {
that.change(prevHeader, true); that.change(prevHeader, true);
} }
} else if(index !== data.index) { // 自动切换到活动标签(功能可取消) } else if(index !== data.index) { // 自动切换到活动标签
that.change(that.findHeaderItem(index), true); that.change(headerItem, true);
} }
} }
// 执行批量关闭标签 // 执行批量关闭标签
if (mode === 'other') { // 关闭其他标签 headers.each(function(i) {
headers.eq(index).siblings(FILTER).remove(); var $this = $(this);
bodys.eq(index).siblings(FILTER).remove(); var layid = $this.attr('lay-id');
} else if(mode === 'right') { // 关闭右侧标签 var bodyItem = that.findBodyItem(layid || i);
headers.filter(':gt('+ index +')'+ FILTER).remove();
bodys.filter(':gt('+ index +')'+ FILTER).remove(); // 标签是否不可关闭
} else { // 关闭所有标签 if ($this.attr('lay-closable') === 'false') {
headers.filter(FILTER).remove(); return;
bodys.filter(FILTER).remove(); }
}
// 批量关闭方式
var isCloseOther = mode === 'other' && i !== itemIndex; // 关闭其他标签
var isCloseRight = mode === 'right' && i > itemIndex; // 关闭右侧标签
var isCloseLeft = mode === 'left' && i < itemIndex; // 关闭左侧标签(不推荐)
var isCloseAll = mode === 'all'; // 关闭所有标签
if (isCloseOther || isCloseRight || isCloseLeft || isCloseAll) {
$this.remove();
bodyItem.remove();
}
});
that.roll('auto'); that.roll('auto');
// 回调 // 回调
var params = that.data(); var data = that.data();
// 标签关闭后的事件 // 标签关闭后的事件
layui.event.call( layui.event.call(
params.thisHeaderItem[0], data.thisHeaderItem[0],
component.CONST.MOD_NAME, component.CONST.MOD_NAME,
'afterClose('+ options.id +')', 'afterClose('+ options.id +')',
params data
); );
}; };
@ -361,6 +370,7 @@ layui.define('component', function(exports) {
var that = this; var that = this;
var options = that.config; var options = that.config;
var layid = thisHeaderItem.attr('lay-id');
var index = thisHeaderItem.index(); var index = thisHeaderItem.index();
var thatA = thisHeaderItem.find('a'); var thatA = thisHeaderItem.find('a');
// 是否存在跳转链接 // 是否存在跳转链接
@ -374,7 +384,7 @@ layui.define('component', function(exports) {
} }
// 当前标签相关数据 // 当前标签相关数据
var params = that.data(); var data = that.data();
// 标签关闭前的事件。若非强制关闭,可则根据事件的返回结果决定是否关闭 // 标签关闭前的事件。若非强制关闭,可则根据事件的返回结果决定是否关闭
if (!force) { if (!force) {
@ -382,13 +392,13 @@ layui.define('component', function(exports) {
thisHeaderItem[0], thisHeaderItem[0],
component.CONST.MOD_NAME, component.CONST.MOD_NAME,
'beforeChange('+ options.id +')', 'beforeChange('+ options.id +')',
$.extend(params, { $.extend(data, {
from: { from: {
index: params.index, index: data.index,
headerItem: params.thisHeaderItem headerItem: data.thisHeaderItem
}, },
to: { to: {
index: thisHeaderItem.index(), index: index,
headerItem: thisHeaderItem headerItem: thisHeaderItem
} }
}) })
@ -405,20 +415,20 @@ layui.define('component', function(exports) {
.removeClass(component.CONST.CLASS_THIS); .removeClass(component.CONST.CLASS_THIS);
// 执行标签内容切换 // 执行标签内容切换
that.findBodyItem(index).addClass(component.CONST.CLASS_SHOW) that.findBodyItem(layid || index).addClass(component.CONST.CLASS_SHOW)
.siblings().removeClass(component.CONST.CLASS_SHOW); .siblings().removeClass(component.CONST.CLASS_SHOW);
that.roll('auto', index); that.roll('auto', index);
// 重新获取标签相关数据 // 重新获取标签相关数据
var params = that.data(); var data = that.data();
// 标签切换后的事件 // 标签切换后的事件
layui.event.call( layui.event.call(
params.thisHeaderItem[0], data.thisHeaderItem[0],
component.CONST.MOD_NAME, component.CONST.MOD_NAME,
'afterChange('+ options.id +')', 'afterChange('+ options.id +')',
params data
); );
}; };
@ -431,17 +441,8 @@ layui.define('component', function(exports) {
var options = that.config; var options = that.config;
var headerItem = $(opts.headerItem || options.headerItem || '<li></li>'); var headerItem = $(opts.headerItem || options.headerItem || '<li></li>');
headerItem.html(opts.title || 'New Tab'); headerItem.html(opts.title || 'New Tab').attr('lay-id', opts.id);
that.appendClose(headerItem, opts); // 追加标签关闭元素
// 追加属性
layui.each(opts, function(key, value){
if(/^(title|content|mode|done)$/.test(key)) return;
headerItem.attr('lay-'+ key, value);
});
// 追加标签关闭元素
that.appendClose(headerItem, opts);
return headerItem; return headerItem;
}; };
@ -450,11 +451,11 @@ layui.define('component', function(exports) {
* @param {Object} opts - 标签项配置信息 * @param {Object} opts - 标签项配置信息
*/ */
Class.prototype.renderBodyItem = function(opts) { Class.prototype.renderBodyItem = function(opts) {
var that = this var that = this;
var options = that.config var options = that.config;
var bodyItem = $(opts.bodyItem || options.bodyItem || '<div class="'+ component.CONST.ITEM +'"></div>'); var bodyItem = $(opts.bodyItem || options.bodyItem || '<div class="'+ component.CONST.ITEM +'"></div>');
bodyItem.html(opts.content || ''); bodyItem.html(opts.content || '').attr('lay-id', opts.id);
return bodyItem; return bodyItem;
}; };
@ -472,7 +473,11 @@ layui.define('component', function(exports) {
opts = opts || {}; opts = opts || {};
// 不可关闭项 // 不可关闭项
if (opts.closable === 'false' || headerItem.attr('lay-closable') === 'false') { if (opts.closable == false) {
headerItem.attr('lay-closable', 'false');
}
if (headerItem.attr('lay-closable') === 'false') {
return; return;
} }
@ -493,16 +498,15 @@ layui.define('component', function(exports) {
var options = that.config; var options = that.config;
var container = that.getContainer(); var container = that.getContainer();
// 是否开启关闭 container.header.items.each(function() {
if (options.closable) { var $this = $(this);
container.header.items.each(function() { // 是否开启关闭
that.appendClose($(this)); if (options.closable) {
}); that.appendClose($this);
} else { } else {
container.header.items.each(function() { $this.find('.'+ component.CONST.CLOSE).remove();
$(this).find('.'+ component.CONST.CLOSE).remove(); }
}); });
}
}; };
/** /**
@ -652,25 +656,41 @@ layui.define('component', function(exports) {
}; };
/** /**
* 根据 id index 获取相关标签头部项 * 获取标签头部项
* @param {number|string} index - 标签索引或 id * @param {number|string} index - 标签索引或 lay-id
*/ */
Class.prototype.findHeaderItem = function(index) { Class.prototype.findHeaderItem = function(index) {
if(!( var container = this.getContainer();
typeof index === 'number' var headerItems = container.header.items;
|| (typeof index === 'string' && index)
)) return; // 根据 lay-id 匹配
var headerItems = this.getContainer().header.items; if (typeof index === 'string') {
var item = headerItems.filter('[lay-id="'+ index +'"]'); return headerItems.filter('[lay-id="'+ index +'"]');
return item[0] ? item : headerItems.eq(index); }
return headerItems.eq(index);
}; };
/** /**
* 根据 index 获取相关标签内容项 * 获取标签内容项
* @param {number} index - 标签索引 * @param {number|string} index - 标签索引lay-id
*/ */
Class.prototype.findBodyItem = function(index) { Class.prototype.findBodyItem = function(index) {
return this.getContainer().body.items.eq(index); var container = this.getContainer();
var bodyItems = container.body.items;
// 根据 lay-id 匹配
if (typeof index === 'string') {
var bodyItem = bodyItems.filter('[lay-id="'+ index +'"]');
return bodyItem[0] ? bodyItem : function() {
// 若未匹配到 lay-id 对应内容项,则通过对应头部项的索引匹配内容项
var headerItems = container.header.items;
var headerItem = headerItems.filter('[lay-id="'+ index +'"]');
return bodyItems.eq(headerItem.index());
}();
}
return bodyItems.eq(index);
}; };
/** /**
@ -687,11 +707,11 @@ layui.define('component', function(exports) {
return { return {
options: options, // 标签配置信息 options: options, // 标签配置信息
container: container, // 标签容器的相关元素 container: container, // 标签容器的相关元素
thisHeaderItem: thisHeaderItem, // 当前标签头部项 thisHeaderItem: thisHeaderItem, // 当前活动标签头部项
thisBodyItem: that.findBodyItem(index), // 当前标签内容项 thisBodyItem: that.findBodyItem(index), // 当前活动标签内容项
index: index, // 当前标签索引 index: index, // 当前活动标签索引
length: container.header.items.length // 当前标签数 length: container.header.items.length // 标签数
} };
}; };
// 扩展组件接口 // 扩展组件接口
@ -715,8 +735,11 @@ layui.define('component', function(exports) {
*/ */
close: function(id, index, force) { close: function(id, index, force) {
var that = component.getInst(id); var that = component.getInst(id);
if(!that) return; if (!that) return;
if(index === undefined) index = that.data().index; // index 若不传,则表示关闭当前标签 // index 若不传,则表示关闭当前标签
if (index === undefined) {
index = that.data().index;
}
that.close(that.findHeaderItem(index), force); that.close(that.findHeaderItem(index), force);
}, },
@ -726,10 +749,10 @@ layui.define('component', function(exports) {
* @param {('other'|'right'|'all')} [mode="all"] - 关闭方式 * @param {('other'|'right'|'all')} [mode="all"] - 关闭方式
* @param {number} index - 活动标签的索引默认取当前选中标签的索引一般用于标签右键事件 * @param {number} index - 活动标签的索引默认取当前选中标签的索引一般用于标签右键事件
*/ */
closeMult: function(id, mode, index, force) { closeMult: function(id, mode, index) {
var that = component.getInst(id); var that = component.getInst(id);
if(!that) return; if(!that) return;
that.closeMult(mode, index, force); that.closeMult(mode, index);
}, },
/** /**
@ -755,7 +778,7 @@ layui.define('component', function(exports) {
/** /**
* 获取标签指定头部项 * 获取标签指定头部项
* @param {string} id - 渲染时的实例 ID * @param {string} id - 渲染时的实例 ID
* @param {number} index - 标签索引 * @param {number} index - 标签索引lay-id
* @returns * @returns
*/ */
getHeaderItem: function(id, index) { getHeaderItem: function(id, index) {
@ -767,7 +790,7 @@ layui.define('component', function(exports) {
/** /**
* 获取标签指定内容项 * 获取标签指定内容项
* @param {string} id - 渲染时的实例 ID * @param {string} id - 渲染时的实例 ID
* @param {number} index - 标签索引 * @param {number} index - 标签索引lay-id
* @returns * @returns
*/ */
getBodyItem: function(id, index) { getBodyItem: function(id, index) {

View File

@ -145,7 +145,8 @@ layui.define(['laytpl', 'form'], function(exports) {
// 解析模板 // 解析模板
var thisElem = that.elem = $(laytpl(TPL_MAIN, { var thisElem = that.elem = $(laytpl(TPL_MAIN, {
open: '{{', // 标签符前缀 open: '{{', // 标签符前缀
close: '}}' // 标签符后缀 close: '}}', // 标签符后缀
tagStyle: 'legacy'
}).render({ }).render({
data: options, data: options,
index: that.index // 索引 index: that.index // 索引

View File

@ -590,7 +590,7 @@ layui.define(['table'], function (exports) {
})() })()
// 优化参数,添加一个 getNodeByIndex 方法 只传 表格id 和行 dataIndex 分几步优化 todo // 优化参数,添加一个 getNodeByIndex 方法 只传 表格id 和行 dataIndex 分几步优化 todo
var expandNode = function (treeNode, expandFlag, sonSign, focus, callbackFlag) { var expandNode = function (treeNode, expandFlag, sonSign, focus, callbackFlag, done) {
// treeNode // 需要展开的节点 // treeNode // 需要展开的节点
var trElem = treeNode.trElem; var trElem = treeNode.trElem;
var tableViewElem = treeNode.tableViewElem || trElem.closest(ELEM_VIEW); var tableViewElem = treeNode.tableViewElem || trElem.closest(ELEM_VIEW);
@ -658,7 +658,7 @@ layui.define(['table'], function (exports) {
tableViewElem: tableViewElem, tableViewElem: tableViewElem,
tableId: tableId, tableId: tableId,
options: options, options: options,
}, expandFlag, sonSign, focus, callbackFlag); }, expandFlag, sonSign, focus, callbackFlag, done);
} else if (item1[LAY_EXPAND]) { // 初始化级联展开 } else if (item1[LAY_EXPAND]) { // 初始化级联展开
expandNode({ expandNode({
dataIndex: item1[LAY_DATA_INDEX], dataIndex: item1[LAY_DATA_INDEX],
@ -666,7 +666,7 @@ layui.define(['table'], function (exports) {
tableViewElem: tableViewElem, tableViewElem: tableViewElem,
tableId: tableId, tableId: tableId,
options: options, options: options,
}, true); }, true, undefined, undefined, undefined, done);
} }
}); });
} else { } else {
@ -681,7 +681,7 @@ layui.define(['table'], function (exports) {
trData[LAY_ASYNC_STATUS] = 'success'; trData[LAY_ASYNC_STATUS] = 'success';
trData[customName.children] = data; trData[customName.children] = data;
treeTableThat.initData(trData[customName.children], trData[LAY_DATA_INDEX]) treeTableThat.initData(trData[customName.children], trData[LAY_DATA_INDEX])
expandNode(treeNode, true, isToggle ? false : sonSign, focus, callbackFlag); expandNode(treeNode, true, isToggle ? false : sonSign, focus, callbackFlag, done);
} }
var format = asyncSetting.format; // 自定义数据返回方法 var format = asyncSetting.format; // 自定义数据返回方法
@ -804,7 +804,7 @@ layui.define(['table'], function (exports) {
tableViewElem: tableViewElem, tableViewElem: tableViewElem,
tableId: tableId, tableId: tableId,
options: options, options: options,
}, expandFlag, sonSign, focus, callbackFlag); }, expandFlag, sonSign, focus, callbackFlag, done);
}) })
} }
} }
@ -820,7 +820,7 @@ layui.define(['table'], function (exports) {
tableViewElem: tableViewElem, tableViewElem: tableViewElem,
tableId: tableId, tableId: tableId,
options: options, options: options,
}, expandFlag, sonSign, focus, callbackFlag); }, expandFlag, sonSign, focus, callbackFlag, done);
}); });
tableViewElem.find(childNodes.map(function (value, index, array) { // 只隐藏直接子节点,其他由递归的处理 tableViewElem.find(childNodes.map(function (value, index, array) { // 只隐藏直接子节点,其他由递归的处理
return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]' return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'
@ -843,6 +843,10 @@ layui.define(['table'], function (exports) {
layui.type(onExpand) === 'function' && onExpand(tableId, trData, trExpand); layui.type(onExpand) === 'function' && onExpand(tableId, trData, trExpand);
} }
if(layui.type(done) === 'function' && trData[LAY_ASYNC_STATUS] !== 'loading'){
done(tableId, trData, trExpand);
}
return retValue; return retValue;
} }
@ -853,7 +857,8 @@ layui.define(['table'], function (exports) {
* @param {Number|String} opts.index 展开行的数据下标 * @param {Number|String} opts.index 展开行的数据下标
* @param {Boolean} [opts.expandFlag] 展开关闭切换 * @param {Boolean} [opts.expandFlag] 展开关闭切换
* @param {Boolean} [opts.inherit] 是否级联子节点 * @param {Boolean} [opts.inherit] 是否级联子节点
* @param {Boolean} [opts.callbackFlag] 是否触发事件 * @param {Boolean} [opts.callbackFlag] 是否触发 tree.callback 事件
* @param {Boolean} [opts.done] 节点操作完成后的回调函数
* @return [{Boolean}] 状态结果 * @return [{Boolean}] 状态结果
* */ * */
treeTable.expandNode = function (id, opts) { treeTable.expandNode = function (id, opts) {
@ -871,7 +876,7 @@ layui.define(['table'], function (exports) {
var tableViewElem = options.elem.next(); var tableViewElem = options.elem.next();
return expandNode({ return expandNode({
trElem: tableViewElem.find('tr[lay-data-index="' + index + '"]').first() trElem: tableViewElem.find('tr[lay-data-index="' + index + '"]').first()
}, expandFlag, sonSign, null, callbackFlag) }, expandFlag, sonSign, null, callbackFlag, opts.done)
}; };
/** /**

View File

@ -348,25 +348,24 @@ layui.define('jquery', function(exports) {
// 转义 html // 转义 html
escape: function(html){ escape: function(html){
var exp = /[<"'>]|&(?=#[a-zA-Z0-9]+)/g; var exp = /[<"'>]|&(?=#?[a-zA-Z0-9]+)/g;
if(html === undefined || html === null) return ''; if (html === undefined || html === null) return '';
html += ''; html += '';
if(!exp.test(html)) return html; if (!exp.test(html)) return html;
return html.replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;') return html.replace(/&(?=#?[a-zA-Z0-9]+;?)/g, '&amp;')
.replace(/</g, '&lt;').replace(/>/g, '&gt;') .replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/'/g, '&#39;').replace(/"/g, '&quot;'); .replace(/'/g, '&#39;').replace(/"/g, '&quot;');
}, },
// 还原转义的 html // 还原转义的 html
unescape: function(html){ unescape: function(html){
if(html === undefined || html === null) html = ''; if (html === undefined || html === null) return '';
html += '';
return html.replace(/\&amp;/g, '&') return String(html).replace(/\&quot;/g, '"').replace(/\&#39;/g, '\'')
.replace(/\&lt;/g, '<').replace(/\&gt;/g, '>') .replace(/\&gt;/g, '>').replace(/\&lt;/g, '<')
.replace(/\&#39;/g, '\'').replace(/\&quot;/g, '"'); .replace(/\&amp;/g, '&');
}, },
// 打开新窗口 // 打开新窗口