Merge pull request #1267 from layui/2.x

release v2.8.4
pull/1269/head^2 v2.8.4
贤心 2023-05-30 10:26:48 +08:00 committed by GitHub
commit 9a0c84a688
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 838 additions and 207 deletions

View File

@ -35,5 +35,5 @@ body:
attributes:
label: 友好承诺
options:
- label: 我承诺将本着相互尊重、理解和友善的态度进行交流,共同维护 Layui 来之不易的良好的社区氛围。
- label: 我承诺将本着相互尊重、理解和友善的态度进行交流,共同维护 Layui 良好的社区氛围。
required: true

View File

@ -7,13 +7,13 @@ body:
id: related-problem
attributes:
label: 建议内容
description: 阐述提出该建议的出发点。
placeholder: 阐述提出该建议的出发点。
validations:
required: true
- type: textarea
id: desired-solution
attributes:
label: 解决方案
description: 您希望看到什么样的解决方案?
placeholder: 您希望看到什么样的解决方案?
validations:
required: true

View File

@ -1,6 +1,6 @@
### 😃 本次 PR 的变化性质
> 请至少勾选一项([ ] 内填写 x
> 请至少勾选一项([ ] 内填写 x
- [ ] 功能新增
- [x] 问题修复
@ -10,12 +10,12 @@
### 🌱 本次 PR 的变化内容
- 在此处尽可能列出本次 PR 的每一项改动内容
- 在此处列出本次 PR 的每一项改动内容
### ✅ 本次 PR 的满足条件
> 请在申请合并之前,将符合条件的每一项进行勾选([ ] 内填写 x
> 请在申请合并之前,将符合条件的每一项进行勾选([ ] 内填写 x
- [ ] 已提供在线演示地址(如:[codepen](https://codepen.io/))或无需演示
- [ ] 已对每一项的改动均测试通过

2
dist/css/layui.css vendored

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

View File

@ -18,7 +18,20 @@ toc: true
<input type="checkbox" name="AAA" title="默认">
<input type="checkbox" name="BBB" lay-text="选中" checked>
<input type="checkbox" name="CCC" title="禁用" disabled>
<input type="checkbox" name="DDD" title="半选" id="ID-checkbox-ind">
</div>
<!-- import layui -->
<script>
layui.use(function(){
var form = layui.form;
var $ = layui.$;
// 初始设置半选
$('#ID-checkbox-ind').prop('indeterminate', true); // 半选属性只能动态设置
form.render('checkbox');
});
</script>
</textarea>
</pre>
@ -41,7 +54,7 @@ toc: true
<div class="layui-form">
<input type="checkbox" name="AAA" title="默认" lay-skin="tag">
<input type="checkbox" name="BBB" title="选中" lay-skin="tag" checked>
<input type="checkbox" name="CCC" title="禁用" lay-skin="tag" disabled>
<input type="checkbox" name="CCC" title="禁用" lay-skin="tag" disabled>
</div>
<!-- import layui -->
@ -109,9 +122,12 @@ toc: true
<h2 id="on" lay-toc="{hot: true}">复选框事件</h2>
`form.on('checkbox(filter)', callback);`
| 风格 | 事件 |
| --- | --- |
| 默认风格 / 标签风格 | `form.on('checkbox(filter)', callback);` |
| 开关风格 | `form.on('switch(filter)', callback);` |
- `checkbox` 为复选框事件固定名称
- `checkbox` `switch` 为复选框事件固定名称
- `filter` 为复选框元素对应的 `lay-filter` 属性值
该事件在复选框选中或取消选中时触发。

View File

@ -51,7 +51,7 @@
<a href="javascript:;"><i class="layui-icon layui-icon-login-wechat" style="color: #4daf29;"></i></a>
<a href="javascript:;"><i class="layui-icon layui-icon-login-weibo" style="color: #cf1900;"></i></a>
</span>
<a href="#reg">注册帐号</a></span>
<a href="#reg">注册帐号</a>
</div>
</div>
</form>

View File

@ -69,7 +69,7 @@
<a href="javascript:;"><i class="layui-icon layui-icon-login-wechat" style="color: #4daf29;"></i></a>
<a href="javascript:;"><i class="layui-icon layui-icon-login-weibo" style="color: #cf1900;"></i></a>
</span>
<a href="#login">登录已有帐号</a></span>
<a href="#login">登录已有帐号</a>
</div>
</div>
</form>

View File

@ -89,8 +89,8 @@ form 还可以借助*栅格*实现更灵活的响应式布局。
| [form.val(filter, obj)](#val) | 表单赋值或取值。 [#用法](#val) |
| [form.submit(filter, callback)](#submit) <sup>2.7+</sup> | 用于主动执行指定表单的提交。[#用法](#submit) |
| [form.on(\'event(filter)\', callback)](#on) | 事件。[#用法](#on) |
| [form.set(options)](#set) | 设置 form 组件全局配置项。 |
| form.config | 获取 form 组件全局配置项。 |
| form.set(options) | 设置 form 组件全局配置项。 |
<h2 id="attr" lay-toc="{level: 2}">属性</h2>
@ -228,7 +228,7 @@ Layui 对表单做了相对巧妙的支持,只需在表单元素上设置 `lay
当内置的验证规则无法满足业务需求时,我们可以通过该方法自定义验证规则。如:
<pre class="layui-code" lay-options="{preview: true, done: function(obj){
<pre class="layui-code" lay-options="{preview: true, codeStyle: 'height: 508px;', done: function(obj){
obj.render()
}}">
<textarea>
@ -248,7 +248,7 @@ Layui 对表单做了相对巧妙的支持,只需在表单元素上设置 `lay
- 参数 `elem` 为元素选择器或 jQuery 对象; 若验证通过,该方法将返回 true否则返回 false
<pre class="layui-code" lay-options="{preview: true, done: function(obj){
<pre class="layui-code" lay-options="{preview: true, codeStyle: 'height: 508px;', done: function(obj){
obj.render()
}}">
<textarea>
@ -281,7 +281,7 @@ Layui 对表单做了相对巧妙的支持,只需在表单元素上设置 `lay
在表单域中,对指定按钮设置 `lay-submit` 属性,即意味着点击该按钮时,将触发提交事件。如:
<pre class="layui-code" lay-options="{preview: true, done: function(obj){
<pre class="layui-code" lay-options="{preview: true, codeStyle: 'height: 508px;', done: function(obj){
obj.render()
}}">
<textarea>
@ -332,7 +332,7 @@ layui.use(function(){
使用该方法可以实现在任意位置对指定表单的主动提交,相比上述的提交事件更加灵活。
<pre class="layui-code" lay-options="{preview: true, done: function(obj){
<pre class="layui-code" lay-options="{preview: true, codeStyle: 'height: 508px;', done: function(obj){
obj.render()
}}">
<textarea>
@ -397,4 +397,23 @@ form.on('select', function(data){
form.on('select(test)', function(data){
console.log(data);
});
```
```
<h2 id="set" class="ws-anchor">全局设置</h2>
`form.set(options);`
- 参数 `options` : 全局属性配置项。详见下表:
| 属性名 | 描述 | 类型 | 默认值 |
| --- | --- | --- | --- |
| autocomplete | 设置 input 框的 `autocomplete` 属性初始值 | string | - |
| verIncludelRequired <sup>2.8.4+</sup> | 验证规则中是否同时包含必填。 form 组件在 `2.8.3` 版本中调整了内置校验规则,即:仅当非空时进行校验,避免强制携带必填的校验规则。如需保留之前的验证规则(即同时校验必填),可将该属性设置为 `true`。但一般还是建议将必填项放置在 `lay-verify` 属性上,如: `lay-verify="required\|number"` | boolean | `false` |
该方法用于对 form 组件进行全局设置。
```
form.set({
autocomplete: 'off' // 阻止 input 框默认的自动输入完成功能
});
```

View File

@ -81,7 +81,7 @@ npm i layui
现在,让我们以一个最简单的示例开始入门:
<pre class="layui-code" lay-options="{preview: 'iframe', previewStyle: 'height: 210px;'}">
<pre class="layui-code" lay-options="{preview: 'iframe', previewStyle: 'height: 210px;', copy: true, tools: []}">
<textarea>
<!DOCTYPE html>
<html>

View File

@ -183,6 +183,13 @@ value: '2018-08-18'
value: new Date(1534766888000) // 参数即为2018-08-20 20:08:08 的毫秒数
```
- 当开启 `range` 时,初始设置日期范围值
```
// 开始日期 - 结束日期
value: '1900-01-01 - 2100-01-01'
```
</td>
<td>string<br>date</td>
<td>
@ -429,6 +436,7 @@ btns: ['clear', 'confirm']
<td>
是否在选中目标值时即自动确认。
<br>当开启 `range` 属性时,该属性无效。
</td>
<td>boolean</td>
@ -479,6 +487,13 @@ theme: '#FF5722'
theme: ['grid', '#FF5722']
```
若第 1 个成员为 hex 格式的主色值,则第 2 个成员为辅色值
```
// 主色、辅色 --- 2.8.4 新增
theme: ['#16baaa', '#16b777']
```
效果及用法详见: [#示例](#demo-theme)
</td>

View File

@ -16,6 +16,8 @@
<h3 id="demo-alert" lay-toc="{level: 3}">信息框</h3>
信息框即 `dialog` 类型层,对应默认的 `type: 0`,该类型的弹层同时只能存在一个。更多说明详见:[#type](#options)
<pre class="layui-code" lay-options="{preview: true, codeStyle: 'height: 535px;', layout: ['preview', 'code'], tools: ['full']}">
<textarea>
{{- d.include("/layer/examples/alert.md") }}

View File

@ -20,11 +20,11 @@
弹层类型。 可选值有:
- `0` dialog 信息框
- `1` page 页面层
- `2` iframe 内联框架层
- `3` loading 加载层
- `4` tips 贴士层
- `0` dialog 信息框(默认),*同时只能存在一个层*
- `1` page 页面层*可同时存在多个层*
- `2` iframe 内联框架层*可同时存在多个层*
- `3` loading 加载层*同时只能存在一个层*
- `4` tips 贴士层*可配置同时存在多个层*
`layer` 弹层由以上 5 种类型构成。 不同的类型代表不同的弹出形态,`layer` 提供的所有的弹出方式均由此衍生。

View File

@ -1,13 +1,12 @@
<pre class="layui-code" lay-options="{preview: true, layout: ['preview'], tools: ['full']}">
<textarea>
{{!
<style>
.laytpl-demo{border: 1px solid #eee;}
.laytpl-demo:first-child{border-right: none;}
.laytpl-demo>textarea{position: relative; display: block; width:100%; height: 300px; padding: 11px; border: 0; box-sizing: border-box; resize: none; background-color: #fff; font-family: Courier New; font-size: 13px;}
.laytpl-demo>div:first-child{height: 32px; line-height: 32px; padding: 6px 11px; border-bottom: 1px solid #eee; background-color: #F8F9FA;}
</style>
<pre class="layui-code" lay-options="{preview: true, layout: ['preview'], tools: ['full']}">
<textarea>
{{!
<div class="layui-row">
<div class="layui-col-xs6 laytpl-demo">
<div>模板</div>
@ -72,6 +71,7 @@
</div>
<div class="layui-clear"></div>
<!-- import layui -->
<script>
layui.use(function(){
var laytpl = layui.laytpl;

View File

@ -166,7 +166,9 @@
</textarea>
</pre>
<h3 id="demo-setRowChecked" lay-toc="{level: 2}" class="ws-bold">选中行操作</h3>
<h3 id="demo-setRowChecked" lay-toc="{level: 2, hot: true}" class="ws-bold">选中行操作</h3>
点击行任意处,通过行事件中执行相关选中方法,实现对整行的状态选中。
<pre class="layui-code" lay-options="{preview: true, codeStyle: 'height: 508px;', layout: ['preview', 'code'], tools: ['full'], toolsEvent: function(oi, type){
if(type === 'full'){

View File

@ -54,6 +54,10 @@
直接赋值数据。既适用于只展示一页数据,也能对一段已知数据进行多页展示。该属性与 `url` 属性只能二选一。
<hr>
**注**:当设置 `data` 模式时,`count` 的值取 `data.length`,即对一段已知数据进行分页展示。 此时在 `page` 属性中设置 `count` 无效。 若要在同一页显示所有数据,可将 `limit` 设置成 `data.length`,即与 `count` 等同即可,那么默认的分页栏只会显示 1 页,若要自定义分页结构,可通过 `pagebar` 属性结合 `laypage` 组件来重新自定义分页排版。
</td>
<td>array</td>
<td>-</td>

View File

@ -37,7 +37,9 @@ layui.use('table', function(){
var data = obj.data; // 获取当前行数据
// 显示 - 仅用于演示
layer.msg('当前行数据:<br>'+ JSON.stringify(data));
layer.msg('当前行数据:<br>'+ JSON.stringify(data), {
offset: '65px'
});
// 标注当前点击行的选中状态
obj.setRowChecked({

View File

@ -298,7 +298,7 @@ console.log(checkStatus.isAll ) // 表格是否全选
| --- | --- | --- | --- |
| type | 选中方式。可选值: `checkbox,radio` | string | `checkbox` |
| index | 选中行的下标。即数据的所在数组下标(`0` 开头)。<br>可设置 `all` 表示全选。 | number<br>string | - |
| checked | 选中状态值。 若为 `false` 可取消选中。 | boolean | `true` |
| checked | 选中状态值。 <ul><li>若传递该属性,则赋值固定值。</li><li>若不传递该属性(默认),则 `checkbox` 将在 `true\|false` 中自动切换值,而 `radio` 将赋值 `true` 固定值。<sup>2.8.4+</sup></li></ul> | boolean | - |
| selectedStyle | 是否仅设置样式状态。若为 `true` 则只标注选中样式,不对数据中的 `LAY_CHECKED` 属性赋值。 | boolean | `false` |
该方法用于设置行的选中样式及相关的特定属性值 `LAY_CHECKED`
@ -640,7 +640,8 @@ table.on('colToggled(test)', function(obj){
- 行单击事件:`table.on('row(filter)', callback);`
- 行双击事件:`table.on('rowDouble(filter)', callback);`
单击或双击 table 行任意区域触发,两者用法相同。
单击或双击 table 行任意区域触发,两者用法相同。<br>
<sup>2.8.4+</sup>:在 table 模板中或任意内部元素中设置 `lay-unrow` 属性,可阻止该元素执行 `row` 事件
```js
var table = layui.table;

View File

@ -113,7 +113,7 @@
<td>number</td>
<td>
`340`
`360`
</td>
</tr>

View File

@ -59,6 +59,7 @@ treeTable.render({
| name | 自定义「节点」属性名 | string | `name` |
| id | 自定义「节点索引」属性名 | string | `id` |
| pid | 自定义「父节点索引」属性名 | string | `parentId` |
| icon | 自定义图标的属性名称 | string | `icon` |
</td>
</tr>
@ -118,12 +119,40 @@ treeTable.render({
| --- | --- | --- | --- |
| enable | 是否开启异步加载模式。只有开启时 `async` 的其他属性配置才有效。 **注意:** 异步加载子节点不应跟 `simpleData` 同时开启,可以是 `url+simpleData` 的方式,获取完整的简单数据进行转换。若开启异步加载模式,即表示按需异步加载子节点。 | boolean | `false` |
| url | 异步加载的接口,可以根据需要设置与顶层接口不同的接口,若相同可不设置该属性 | string | - |
| [format](#options.tree.async.format) | 用于处理异步子节点数据的回调函数,该属性优先级高于 `async.url` 属性。用法详见下文。 | function | - |
| type | 请求的接口类型,设置可缺省同上 | string | - |
| contentType | 提交参数的数据类型,设置可缺省同上 | string | - |
| headers | 提交请求头,设置可缺省同上 | object | - |
| where | 提交参数的数据,设置可缺省同上 | object | - |
| autoParam | 自动参数,可以根据配置项以及当前节点的数据传参,如: `['type', 'age=age', 'parentId=id']` ,那么其请求参数将包含: `{type: '父节点 type', age: '父节点 age', parentId: '父节点 id'}` | array | - |
<div id="options.tree.async.format" class="ws-anchor">
**format 示例**
</div>
```
treeTable.render({
elem: '',
treee: {
enable: true,
async: {
format: function(trData, options, callback){
// trData 为行数据、options 为 treeTable 属性配置项
// callbacck 为子节点的渲染函数
// 可利用该函数对子节点数据进行异步请求或其他格式化处理
var nodeList = [
{id: 111, name: '子节点1'},
{id: 333, name: '子节点3'}
];
callback(nodeList);
}
}
}
})
```
</td>
</tr>
<tr>

View File

@ -27,7 +27,10 @@ toc: true
| [treeTable.render(options)](#render) | treeTable 组件渲染,核心方法。 |
| [treeTable.reload(id, options)](#reload) | 树表完整重载。 |
| [treeTable.reloadData(id, options)](#reload) | 树表数据重载。 |
| [treeTable.reloadAsyncNode(id, index)](#reloadAsyncNode) | 重载异步子节点 |
| [treeTable.getData(id, isSimpleData)](#getData) | 获取树表数据。 |
| [treeTable.getNodeById(id)](#getNodeById) | 获取节点信息集 |
| [treeTable.getNodesByFilter(id, filter, opts)](#getNodesByFilter) | 获取符合过滤规则的节点信息集 |
| [treeTable.getNodeDataByIndex(id, index)](#getNodeDataByIndex) | 通过行元素对应的 `data-index` 属性获取对应行数据。 |
| [treeTable.updateNode(id, index, data)](#updateNode) | 更新行数据。 |
| [treeTable.removeNode(id, index)](#removeNode) | 删除行记录。 |
@ -69,6 +72,30 @@ toc: true
使用方式与 `table` 组件完全相同,具体用法可参考:[table 重载](../table/#reload)
<h3 id="reloadAsyncNode" class="ws-anchor ws-bold">重载异步子节点</h3>
`treeTable.reloadAsyncNode(id, index)`
- 参数 `id` : treeTable 渲染时的 id 属性值
- 参数 `index` : 节点对应的行下标,一般可通过 `<tr>` 元素的 `data-index` 属性获得
该方法用于在异步模式下,对节点进行重载。
```js
// 渲染
treeTable.render({
elem: '', // 绑定元素选择器
id: 'test', // 自定义 id 索引
async: {
enable: true // 开启异步加载模式
}
// 其他属性 …
});
// 重载子节点
treeTable.reloadAsyncNode('test', 0); // 第一行
```
<h3 id="getData" lay-pid="api" class="ws-anchor ws-bold">获取树表数据</h3>
`treeTable.getData(id, isSimpleData);`
@ -90,6 +117,52 @@ var data = treeTable.getData('test'); // 获取第一行的数据
console.log(data);
```
<h3 id="getNodeById" lay-pid="api" class="ws-anchor ws-bold">获取节点信息集</h3>
`treeTable.getNodeById(id)`
- 参数 `id` : treeTable 渲染时的 `id` 属性值
```js
// 渲染
treeTable.render({
elem: '', // 绑定元素选择器
id: 'test', // 自定义 id 索引
// 其他属性 …
});
// 获取节点信息集
var obj = treeTable.getNodeById('test');
console.log(obj);
```
<h3 id="getNodesByFilter" lay-pid="api" class="ws-anchor ws-bold">获取符合过滤规则的节点信息集</h3>
`treeTable.getNodesByFilter(id, filter, opts)`
- 参数 `id` : treeTable 渲染时的 `id` 属性值
- 参数 `filter` : 过滤函数
- 参数 `opts` : 该方法的属性可选项,详见下表:
| 属性名 | 描述 | 类型 | 默认值 |
| --- | --- | --- | --- |
| isSingle | 是否只找到第一个 | boolean | `false` |
| parentNode | 在指定在某个父节点下的子节点中搜索 | object | - |
```js
// 渲染
treeTable.render({
elem: '', // 绑定元素选择器
id: 'test', // 自定义 id 索引
// 其他属性 …
});
// 获取节点信息集
var obj = treeTable.getNodesByFilter('test', function(item){
// 自定义过滤条件
return item.id > 1000;
});
console.log(obj);
```
<h3 id="getNodeDataByIndex" lay-pid="api" class="ws-anchor ws-bold">获取树表对应下标的数据</h3>
@ -107,9 +180,9 @@ treeTable.render({
id: 'test', // 自定义 id 索引
// 其他属性 …
});
// 获取当前页接口数据
var data = treeTable.getNodeDataByIndex('test', 0); // 获取第一行的数据
console.log(data);
// 获取树表对应下标的数据
var obj = treeTable.getNodeDataByIndex('test', 0); // 获取第一行的数据
console.log(obj);
```
<h3 id="updateNode" lay-pid="api" class="ws-anchor ws-bold">更新行数据</h3>
@ -244,8 +317,8 @@ treeTable.expandAll('test', false); // 关闭全部节点
| opts | 描述 | 类型 | 默认值 |
| --- | --- | -- | --- |
| index | 要设置选中状态的行下标或行数据 | number/object | - |
| checked | 选中状态。`true` 选中;`false` 取消选中;`null` 切换。 其中,所为 `radio` 框,则不支持 `null`(切换)。 | boolean | DDD |
| callbackFlag | 是否触发事件,若为 `true`,则 `checked: false` 无效。其对应的事件跟 `table``radio,checkbox` 事件用法一样 | boolean | DDD |
| checked | 选中状态。`true` 选中;`false` 取消选中;`null` 切换。 其中,所为 `radio` 框,则不支持 `null`(切换)。 | boolean | - |
| callbackFlag | 是否触发事件,若为 `true`,则 `checked: false` 无效。其对应的事件跟 `table``radio,checkbox` 事件用法一样 | boolean | `false` |
```js
// 渲染

View File

@ -149,7 +149,7 @@ acceptMime: 'image/jpeg, image/png` // 只筛选 jpg,png 格式图片
</div>
- 假设 `accept: 'file'` 类型时,那么设置 `exts: 'zip|rar|7z'` 即代表只允许上传压缩格式的文件。
- 默认为常见图片后缀,即 `exts: 'jpg|png|gif|bmp|jpeg'`
- 默认为常见图片后缀,即 `jpg|png|gif|bmp|jpeg|svg`
</td>
<td>string</td>
@ -342,7 +342,7 @@ before: function(obj){ // obj 参数同 choose
</div>
```
progress: progress: function(n, elem, res, index){
progress: function(n, elem, res, index){
var percent = n + '%' // 获取进度百分比
element.progress('demo', percent); // 可配合 layui 进度条元素使用

View File

@ -11,6 +11,53 @@ toc: true
> 导读:📑 [Layui 2.8 《升级指南》](/notes/2.8/upgrade-guide.html) · 📑 [Layui 新版文档站上线初衷](/notes/2.8/news.html)
<h2 id="2.8.4" class="ws-anchor">
2.8.4
<span class="layui-badge-rim">2023-05-30</span>
</h2>
- #### form
- 新增 `verIncludelRequired` 全局属性,用于设置验证规则中是否同时包含必填 # I737EW
- 修复 checkbox 开关标题和半选图标未垂直居中的问题 # 1255
- 修复 checkbox 在初始设置半选时,点击复选框时图标未恢复成非半选状态的问题
- 修复 checkbox 被重新渲染时,标题模版未正确获取的问题 # 1257
- 修复 select 经浏览器翻译成别的语言后,点击选项出现的显示异常问题 # 1256
- 优化 checkbox 元素的 `lay-skin` ,当设置非内置风格时,不再强制显示为默认风格
- #### table
- 新增 对 table 内元素的 `lay-unrow` 属性的识别,点击该元素时,可阻止执行 `row` 行单击事件
- 修复 `table.setRowChecked()` 方法导致 `checkbox,radio` 事件失效的问题 # I73MLV/I76KBX/I78VI3
- 修复 打印功能在 Edge 中可能出现的闪退问题 # 1264
- 优化 `table.setRowChecked()` 方法,若未传 `checked` 属性,则自动对 `checkbox` 进行选中状态值切换
- 优化 `row` 事件机制,若目标元素为 `checkbox,radio`,则不触发 `row` 事件
- 优化 外层容器的高度,不再设置一个固定值,内部元素将根据 `height` 属性值自动撑满
- 优化 底部边框问题
- #### treeTable
- 新增 节点折叠状态记忆功能 # 1260/I777CJ
- 新增 `customName.icon` 属性,用于自定义图标的属性名称 # 1260/I73BQU
- 新增 `async.format` 回调函数,用于处理异步子节点数据,优先级高于 `async.url` # 1260
- 新增 `treeTable.reloadAsyncNode(id, index)` 方法,用于重载异步子节点 # 1260
- 新增 `treeTable.getNodeById(id)` 方法,用于获取节点信息集 # 1260
- 新增 `treeTable.getNodesByFilter(id, filter, opts)` 方法,用于获取符合过滤规则的节点信息集 # 1260
- 修复 `isSimpleData` 模式渲染后的默认数据排序异常问题 # 1260
- 修复 展开全部节点排序失效的问题 # 1260/I73M2K
- 修复 折叠叶子节点时,图标没有变化的问题 # 1260
- 修复 节点选中状态判断异常问题 # 1260
- 优化 `treeTable.checkStatus()` 方法,可通过设置第二个参数,用于是否返回半选状态的数据 # 1260/I73JAW
- 优化 重新排序和视图内表单初始化的调用逻辑 # 1260
- 优化 节点渲染方法 # 1260
- #### layer
- 修复 `skin:'layui-layer-lan'` 时,导致 `btnAlign` 属性无效的问题 # I73PD1
- #### laydate
- 优化 `theme` 属性,当其为数组格式,且第一个成员为 `hex` 格式主色值,则第二个成员为辅色值 # 1265
- #### upload
- 新增 `exts` 属性对于图片类型时的 `.svg` 扩展名支持
- #### code
- 优化 `copy` 属性开启时, 对 `tools` 属性的初始化配置 # I72QGO
- 优化 `preview: 'iframe'` 时的 `<iframe>` 容器,以支持背景透明
### 下载: [layui-v2.8.4.zip](https://gitee.com/layui/layui/attach_files/1422378/download)
---
<h2 id="2.8.3" class="ws-anchor">
2.8.3

View File

@ -293,6 +293,7 @@
<input type="checkbox" name="like[write]" title="写作">
<input type="checkbox" name="like[read]" title="阅读">
<input type="checkbox" name="like[game]" title="游戏" disabled>
<input type="checkbox" name="like[indeterminate]" id="ID-indeterminate" lay-filter="filter-indeterminate" title="半选">
</div>
</div>
<div class="layui-form-item" pane>
@ -458,6 +459,10 @@
return false;
});
// 设置半选
$('#ID-indeterminate').prop('indeterminate', true);
form.render('checkbox');
// 普通事件
util.on('lay-on', {
"get-vercode": function(othis){

View File

@ -0,0 +1,148 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>表格边框测试</title>
<link rel="stylesheet" href="../src/css/layui.css">
<style>
body {
padding: 32px; /*overflow-y: scroll;*/
}
.layui-table-view {
margin: 8px 0;
}
</style>
</head>
<body>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
<blockquote class="layui-elem-quote">
无统计、无分页
</blockquote>
<table id="test"></table>
<blockquote class="layui-elem-quote">
有统计、无分页
</blockquote>
<table id="test1"></table>
<blockquote class="layui-elem-quote">
无统计、有分页
</blockquote>
<table id="test2"></table>
<blockquote class="layui-elem-quote">
有统计、有分页
</blockquote>
<table id="test3"></table>
<script src="../src/layui.js" src1="https://cdn.staticfile.org/layui/2.7.6/layui.js"></script>
<script>
layui.use(['table', 'laydate'], function () {
var $ = layui.$;
var table = layui.table;
var url = 'json/table/demo1.json';
// 无统计、无分页
table.render({
elem: '#test'
, url: url
// , totalRow: true
, height: 300
, cellMinWidth: 80
//,skin: 'line'
//,size: 'lg'
// , toolbar: true
, cols: [[
{field: 'id', hide: true}
, {field: 'username', title: '用户名'}
, {field: 'email', title: '邮箱'}
, {title: '操作', align: 'center', toolbar: '#barDemo'}
]]
});
// 有统计、无分页
table.render({
elem: '#test1'
, url: url
, totalRow: true
, height: 300
, cellMinWidth: 80
//,skin: 'line'
//,size: 'lg'
// , toolbar: true
, cols: [[
{field: 'id', hide: true}
, {field: 'username', title: '用户名'}
, {field: 'email', title: '邮箱'}
, {title: '操作', align: 'center', toolbar: '#barDemo'}
]]
});
// 无统计、有分页
table.render({
elem: '#test2'
, url: url
//,contentType: 'application/json' // 参数为 json 格式传递
, page: { // 详细参数可参考 laypage 组件文档
curr: 5
, groups: 1
, first: false
, last: false
, layout: ['limit', 'prev', 'page', 'next', 'count'] //自定义分页布局
}
// , totalRow: true
, height: 300
, cellMinWidth: 80
//,skin: 'line'
//,size: 'lg'
// , toolbar: true
, cols: [[
{field: 'id', hide: true}
, {field: 'username', title: '用户名'}
, {field: 'email', title: '邮箱'}
, {title: '操作', align: 'center', toolbar: '#barDemo'}
]]
});
// 有统计、有分页
table.render({
elem: '#test3'
, url: url
//,contentType: 'application/json' // 参数为 json 格式传递
, page: { // 详细参数可参考 laypage 组件文档
curr: 5
, groups: 1
, first: false
, last: false
, layout: ['limit', 'prev', 'page', 'next', 'count'] //自定义分页布局
}
, totalRow: true
, height: 300
, cellMinWidth: 80
//,skin: 'line'
//,size: 'lg'
// , toolbar: true
, cols: [[
{field: 'id', hide: true}
, {field: 'username', title: '用户名'}
, {field: 'email', title: '邮箱'}
, {title: '操作', align: 'center', toolbar: '#barDemo'}
]]
});
});
</script>
</body>
</html>

View File

@ -237,7 +237,8 @@ layui.use(['table', 'dropdown'], function(){
switch(obj.id){
case 'checked':
table.setRowChecked(id, {
index: value
index: value,
checked: true
});
break;
case 'unchecked':

View File

@ -1,6 +1,6 @@
{
"name": "layui",
"version": "2.8.3",
"version": "2.8.4",
"description": "Classic modular Front-End UI library",
"main": "dist/layui.js",
"license": "MIT",

View File

@ -821,7 +821,7 @@ a cite{font-style: normal; *cursor:pointer;}
.layui-form-checkbox{position: relative; display: inline-block; vertical-align: middle; height: 30px; line-height: 30px; margin-right: 10px; padding-right: 30px; background-color: #fff; cursor: pointer; font-size: 0; -webkit-transition: .1s linear; transition: .1s linear; box-sizing: border-box;}
.layui-form-checkbox:hover{}
.layui-form-checkbox > *{display: inline-block; vertical-align: middle;}
.layui-form-checkbox > div{padding: 0 11px; height: 100%; font-size: 14px; border-radius: 2px 0 0 2px; background-color: #d2d2d2; color: #fff; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;}
.layui-form-checkbox > div{padding: 0 11px; font-size: 14px; border-radius: 2px 0 0 2px; background-color: #d2d2d2; color: #fff; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;}
.layui-form-checkbox:hover > div{background-color: #c2c2c2;}
.layui-form-checkbox > i{position: absolute; right: 0; top: 0; width: 30px; height: 100%; border: 1px solid #d2d2d2; border-left: none; border-radius: 0 2px 2px 0; color: #fff; color: rgba(255,255,255,0); font-size: 20px; text-align: center; box-sizing: border-box;}
.layui-form-checkbox:hover > i{border-color: #c2c2c2; color: #c2c2c2;}
@ -838,7 +838,7 @@ a cite{font-style: normal; *cursor:pointer;}
/* 复选框-默认风格 */
.layui-form-checkbox[lay-skin="primary"]{height: auto!important; line-height: normal!important; min-width: 18px; min-height: 18px; border: none!important; margin-right: 0; padding-left: 24px; padding-right: 0; background: none;}
.layui-form-checkbox[lay-skin="primary"] > div{margin-top: -1px; padding-left: 0; padding-right: 15px; line-height: 18px; background: none; color: #5F5F5F;}
.layui-form-checkbox[lay-skin="primary"] > i{right: auto; left: 0; width: 16px; height: 16px; line-height: 16px; border: 1px solid #d2d2d2; font-size: 12px; border-radius: 2px; background-color: #fff; -webkit-transition: .1s linear; transition: .1s linear;}
.layui-form-checkbox[lay-skin="primary"] > i{right: auto; left: 0; width: 16px; height: 16px; line-height: 14px; border: 1px solid #d2d2d2; font-size: 12px; border-radius: 2px; background-color: #fff; -webkit-transition: .1s linear; transition: .1s linear;}
.layui-form-checkbox[lay-skin="primary"]:hover > i{border-color: #16b777; color: #fff;}
.layui-form-checked[lay-skin="primary"] > i{border-color: #16b777 !important; background-color: #16b777; color: #fff;}
.layui-checkbox-disabled[lay-skin="primary"] > div{background: none!important;}
@ -849,7 +849,7 @@ a cite{font-style: normal; *cursor:pointer;}
.layui-form-checkbox[lay-skin="primary"] > .layui-icon-indeterminate:before{content: ''; display: inline-block; vertical-align: middle; position: relative; width: 50%; height: 1px; margin: -1px auto 0; background-color: #16b777;}
/* 复选框-开关风格 */
.layui-form-switch{position: relative; display: inline-block; vertical-align: middle; height: 22px; line-height: 22px; min-width: 35px; padding: 0 5px; margin-top: 8px; border: 1px solid #d2d2d2; border-radius: 20px; cursor: pointer; background-color: #fff; -webkit-transition: .1s linear; transition: .1s linear;}
.layui-form-switch{position: relative; display: inline-block; vertical-align: middle; height: 24px; line-height: 22px; min-width: 44px; padding: 0 5px; margin-top: 8px; border: 1px solid #d2d2d2; border-radius: 20px; cursor: pointer; box-sizing: border-box; background-color: #fff; -webkit-transition: .1s linear; transition: .1s linear;}
.layui-form-switch > i{position: absolute; left: 5px; top: 3px; width: 16px; height: 16px; border-radius: 20px; background-color: #d2d2d2; -webkit-transition: .1s linear; transition: .1s linear;}
.layui-form-switch > div{position: relative; top: 0; margin-left: 21px; padding: 0!important; text-align: center!important; color: #999!important; font-style: normal!important; font-size: 12px;}
.layui-form-onswitch{border-color: #16b777; background-color: #16b777;}
@ -1014,7 +1014,7 @@ a cite{font-style: normal; *cursor:pointer;}
.layui-table-view .layui-table td[data-edit]{cursor: text;}
.layui-table-view .layui-table td[data-edit]:hover:after{position: absolute; left: 0; top: 0; width: 100%; height: 100%; box-sizing: border-box; border: 1px solid #16B777; pointer-events: none; content: "";}
.layui-table-view .layui-form-checkbox[lay-skin="primary"] i{width: 18px; height: 18px;}
.layui-table-view .layui-form-checkbox[lay-skin="primary"] i{width: 18px; height: 18px; line-height: 16px;}
.layui-table-view .layui-form-radio{line-height: 0; padding: 0;}
.layui-table-view .layui-form-radio>i{margin: 0; font-size: 20px;}
.layui-table-init{position: absolute; left: 0; top: 0; width: 100%; height: 100%; text-align: center; z-index: 199;}
@ -1106,7 +1106,7 @@ input.layui-input.layui-table-edit{height: 100%;}
select.layui-table-edit{padding: 0 0 0 10px; border-color: #d2d2d2;}
.layui-table-view .layui-form-switch,
.layui-table-view .layui-form-checkbox,
.layui-table-view .layui-form-radio{top: 0; margin: 0; box-sizing: content-box;}
.layui-table-view .layui-form-radio{top: 0; margin: 0;}
.layui-table-view .layui-form-checkbox{top: -1px; height: 26px; line-height: 26px;}
.layui-table-view .layui-form-checkbox i{height: 26px;}

View File

@ -191,7 +191,7 @@ html #layuicss-layer{display: none; position: absolute; width: 1989px;}
/* 内置 skin */
.layui-layer-lan .layui-layer-title{background:#4476A7; color:#fff; border: none;}
.layui-layer-lan .layui-layer-btn{padding: 5px 10px 10px; text-align: right; border-top:1px solid #E9E7E7}
.layui-layer-lan .layui-layer-btn{padding: 5px 10px 10px; border-top:1px solid #E9E7E7}
.layui-layer-lan .layui-layer-btn a{background: #fff; border-color: #E9E7E7; color: #333;}
.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5;}
.layui-layer-molv .layui-layer-title{background: #009f95; color:#fff; border: none;}

View File

@ -16,7 +16,7 @@
};
var Layui = function(){
this.v = '2.8.3'; // Layui 版本号
this.v = '2.8.4'; // Layui 版本号
};
// 识别预先可能定义的指定全局对象
@ -268,12 +268,13 @@
if(typeof fn === 'string') cssname = fn;
var app = (cssname || href).replace(/\.|\//g, '');
var id = link.id = 'layuicss-'+ app;
var id = 'layuicss-'+ app;
var STAUTS_NAME = 'creating';
var timeout = 0;
link.rel = 'stylesheet';
link.href = href + (config.debug ? '?v='+new Date().getTime() : '');
link.rel = 'stylesheet';
link.id = id;
link.media = 'all';
if(!doc.getElementById(id)){

View File

@ -186,8 +186,15 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
});
// copy
if(options.copy && layui.type(options.tools) === 'array'){
options.tools.unshift('copy');
if(options.copy){
if(layui.type(options.tools) === 'array'){
// 若 copy 未存在于 tools 中,则追加到最前
if(options.tools.indexOf('copy') === -1){
options.tools.unshift('copy');
}
} else {
options.tools = ['copy'];
}
}
// 工具栏事件
@ -217,7 +224,7 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
// 追加预览
if(isIframePreview){
elemPreviewView.html('<iframe></iframe>');
elemPreviewView.html('<iframe allowtransparency="true" frameborder="0"></iframe>');
}
// 执行预览

View File

@ -46,6 +46,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
'请输入正确的身份证号'
]
},
verIncludelRequired: false, // 验证规则是否包含必填 --- 为兼容旧版的验证机制
autocomplete: null // 全局 autocomplete 状态。 null 表示不干预
};
};
@ -658,7 +659,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){
// 半选
if (check[0].indeterminate) {
check[0].indeterminate = false;
reElem.find(CLASS.SUBTRA).removeClass(CLASS.SUBTRA).addClass('layui-icon-ok')
reElem.find('.'+ CLASS.SUBTRA).removeClass(CLASS.SUBTRA).addClass('layui-icon-ok');
}
// 开关
@ -690,6 +691,13 @@ layui.define(['lay', 'layer', 'util'], function(exports){
}()));
var disabled = this.disabled;
// if(!skins[skin]) skin = 'primary'; // 若非内置风格,则强制为默认风格
var RE_CLASS = CLASS[skin] || CLASS.checkbox;
// 替代元素
var hasRender = othis.next('.' + RE_CLASS[0]);
hasRender[0] && hasRender.remove(); // 若已经渲染,则 Rerender
// 若存在标题模板,则优先读取标题模板
if(othis.next('[lay-checkbox]')[0]){
title = othis.next().html() || '';
@ -697,14 +705,10 @@ layui.define(['lay', 'layer', 'util'], function(exports){
// 若为开关,则对 title 进行分隔解析
title = skin === 'switch' ? title.split('|') : [title];
if(!skins[skin]) skin = 'primary'; // 若非内置风格,则强制为默认风格
var RE_CLASS = CLASS[skin] || CLASS.checkbox;
if(typeof othis.attr('lay-ignore') === 'string') return othis.show();
// 替代元素
var hasRender = othis.next('.' + RE_CLASS[0]);
var reElem = $(['<div class="layui-unselect '+ RE_CLASS[0],
(check.checked ? (' '+ RE_CLASS[1]) : ''), // 选中状态
(disabled ? ' layui-checkbox-disabled '+ DISABLED : ''), // 禁用状态
@ -725,7 +729,6 @@ layui.define(['lay', 'layer', 'util'], function(exports){
}(),
'</div>'].join(''));
hasRender[0] && hasRender.remove(); // 如果已经渲染则Rerender
othis.after(reElem);
events.call(this, reElem, RE_CLASS);
});
@ -839,7 +842,8 @@ layui.define(['lay', 'layer', 'util'], function(exports){
Form.prototype.validate = function(elem){
var that = this;
var stop = null; // 验证不通过状态
var verify = form.config.verify; // 验证规则
var options = that.config; // 获取全局配置项
var verify = options.verify; // 验证规则
var DANGER = 'layui-form-danger'; // 警示样式
elem = $(elem);
@ -890,7 +894,13 @@ layui.define(['lay', 'layer', 'util'], function(exports){
}
// 若为必填项或者非空命中校验,则阻止提交,弹出提示
if(isTrue && (thisVer === 'required' || (value && thisVer !== 'required'))){
if(isTrue && (
options.verIncludelRequired || (
thisVer === 'required' || (
value && thisVer !== 'required'
)
)
)){
// 提示层风格
if(verType === 'tips'){
layer.tips(errorText, function(){

View File

@ -657,17 +657,30 @@
});
options.showBottom && elem.appendChild(divFooter);
//生成自定义主题
// 生成自定义主题
var style = lay.elem('style');
var styleText = [];
var colorTheme;
var isPrimaryColor = true;
lay.each(options.theme, function (index, theme) {
if(/^#/.test(theme)){
// 主色
if(isPrimaryColor && /^#/.test(theme)){
colorTheme = true;
isPrimaryColor = false;
styleText.push([
'#{{id}} .layui-laydate-header{background-color:{{theme}};}'
,'#{{id}} li.layui-this,#{{id}} td.layui-this>div{background-color:{{theme}} !important;}'
,options.theme.indexOf('circle') !== -1 ? '' : '#{{id}} .layui-this{background-color:{{theme}} !important;}'
'#{{id}} .layui-laydate-header{background-color:{{theme}};}',
'#{{id}} li.layui-this,#{{id}} td.layui-this>div{background-color:{{theme}} !important;}',
options.theme.indexOf('circle') !== -1 ? '' : '#{{id}} .layui-this{background-color:{{theme}} !important;}',
'#{{id}} .laydate-day-now{color:{{theme}} !important;}',
'#{{id}} .laydate-day-now:after{border-color:{{theme}} !important;}'
].join('').replace(/{{id}}/g, that.elemID).replace(/{{theme}}/g, theme));
return;
}
// 第二个自定义颜色作为辅色
if(!isPrimaryColor && /^#/.test(theme)){
styleText.push([
'#{{id}} .laydate-selected>div{background-color:{{theme}} !important;}',
'#{{id}} .laydate-selected:hover>div{background-color:{{theme}} !important;}'
].join('').replace(/{{id}}/g, that.elemID).replace(/{{theme}}/g, theme));
}
});

View File

@ -404,7 +404,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
,'style': function(){
var arr = [];
if(options.width) arr.push('width:'+ options.width + 'px;');
if(options.height) arr.push('height:'+ options.height + 'px;');
// if(options.height) arr.push('height:'+ options.height + 'px;');
return arr.join('')
}()
}).html(laytpl(TPL_MAIN, {
@ -1450,8 +1450,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
));
opts = $.extend({
type: 'checkbox', // 选中方式
checked: true // 选中状态
type: 'checkbox' // 选中方式
}, opts);
// 标注当前行选中样式
@ -1459,26 +1458,33 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
tr.addClass(ELEM_CLICK).siblings('tr').removeClass(ELEM_CLICK);
}
// 仅设置样式状态
// 仅设置样式状态,不设置数据中的选中属性
if(opts.selectedStyle || selectedStyle) return;
// 同步数据选中属性值
var thisData = table.cache[that.key];
var existChecked = 'checked' in opts;
var getChecked = function(value){
// 若为单选框,则单向选中;若为复选框,则切换选中。
return opts.type === 'radio' ? true : (existChecked ? opts.checked : !value)
};
// 设置数据选中属性
layui.each(thisData, function(i, item){
if(opts.index === i || opts.index === 'all'){
item[options.checkName] = opts.checked;
item[options.checkName] = getChecked(item[options.checkName]);
} else if(opts.type === 'radio') {
delete item[options.checkName];
}
});
// 若存在复选框或单选框,则标注选中样式
tr.find('input[lay-type="'+ ({
// 若存在复选框或单选框,则标注选中状态样式
var checkedElem = tr.find('input[lay-type="'+ ({
radio: 'layTableRadio',
checkbox: 'layTableCheckbox'
}[opts.type] || 'checkbox') +'"]').prop('checked', opts.checked);
}[opts.type] || 'checkbox') +'"]');
checkedElem.prop('checked', getChecked(checkedElem.last().prop('checked')));
that.syncCheckAll();
that.renderForm(opts.type);
@ -1570,10 +1576,10 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
}
};
//请求loading
// 请求 loading
Class.prototype.loading = function(hide){
var that = this
,options = that.config;
var that = this;
var options = that.config;
if(options.loading){
if(hide){
that.layInit && that.layInit.remove();
@ -1588,14 +1594,22 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
}
};
//同步选中值状态
Class.prototype.setCheckData = function(index, checked){
var that = this
,options = that.config
,thisData = table.cache[that.key];
// 同步选中值状态
Class.prototype.setCheckData = function(index, checked, radio){
var that = this;
var options = that.config;
var thisData = table.cache[that.key];
if(!thisData[index]) return;
if(layui.type(thisData[index]) === 'array') return;
thisData[index][options.checkName] = checked;
layui.each(thisData, function(i, item){
if(index === i){
item[options.checkName] = checked;
} else if(radio) { // 是否单选
delete item[options.checkName];
}
});
};
// 同步全选按钮状态
@ -1653,11 +1667,11 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
if(that.fullHeightGap){
height = _WIN.height() - that.fullHeightGap;
if(height < 135) height = 135;
that.elem.css('height', height);
// that.elem.css('height', height);
} else if (that.parentDiv && that.parentHeightGap) {
height = $(that.parentDiv).height() - that.parentHeightGap;
if (height < 135) height = 135;
that.elem.css("height", height);
// that.elem.css("height", height);
}
// 如果多级表头,则填补表头高度
@ -1674,22 +1688,22 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
if(!height) return;
// 减去列头区域的高度 --- 此处的数字常量是为了防止容器处在隐藏区域无法获得高度的问题,暂时只对默认尺寸表格做支持
bodyHeight = parseFloat(height) - (that.layHeader.outerHeight() || 39) - 1;
// 减去列头区域的高度 --- 此处的数字常量是为了防止容器处在隐藏区域无法获得高度的问题,只对默认尺寸表格做支持
bodyHeight = parseFloat(height) - (that.layHeader.outerHeight() || 39)
// 减去工具栏的高度
if(options.toolbar){
bodyHeight -= (that.layTool.outerHeight() || 50);
bodyHeight -= (that.layTool.outerHeight() || 51);
}
// 减去统计栏的高度
if(options.totalRow){
bodyHeight -= (that.layTotal.outerHeight() || 40) - 1; // 减掉一个共用的 border width
bodyHeight -= (that.layTotal.outerHeight() || 40);
}
// 减去分页栏的高度
if(options.page || options.pagebar){
bodyHeight -= (that.layPage.outerHeight() || 43) - 1;
bodyHeight -= (that.layPage.outerHeight() || 43);
}
if (options.maxHeight) {
@ -1904,8 +1918,14 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
printWin.document.write(style + html.prop('outerHTML'));
printWin.document.close();
printWin.print();
printWin.close();
if(layui.device('edg').edg){
printWin.onafterprint = printWin.close;
printWin.print();
}else{
printWin.print();
printWin.close();
}
break;
}
@ -2139,7 +2159,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
};
// 复选框选择(替代元素的 click 事件)
that.elem.on('click', 'input[name="layTableCheckbox"]+', function(){
that.elem.on('click', 'input[name="layTableCheckbox"]+', function(e){
var othis = $(this);
var td = othis.closest('td');
var checkbox = othis.prev();
@ -2161,6 +2181,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
} else {
that.setCheckData(index, checked);
that.syncCheckAll();
layui.stope(e);
}
// 事件
@ -2178,20 +2199,24 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
});
// 单选框选择
that.elem.on('click', 'input[lay-type="layTableRadio"]+', function(){
that.elem.on('click', 'input[lay-type="layTableRadio"]+', function(e){
var othis = $(this);
var td = othis.closest('td');
var radio = othis.prev();
var checked = radio[0].checked;
var index = radio.parents('tr').eq(0).data('index');
if(radio[0].disabled) return;
layui.stope(e);
if(radio[0].disabled) return false;
// 单选框选中状态
// 标注数据中的选中属性
that.setCheckData(index, checked, 'radio');
// 标注选中样式
that.setRowChecked({
type: 'radio',
index: index
});
}, true);
// 事件
layui.event.call(
@ -2217,7 +2242,16 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
var index = othis.index();
if(othis.data('off')) return; // 不触发事件
that.layBody.find('tr:eq('+ index +')').removeClass(ELEM_HOVER)
}).on('click', 'tr', function(){ // 单击行
}).on('click', 'tr', function(e){ // 单击行
// 不支持行单击事件的元素
var UNROW = '.layui-form-checkbox,.layui-form-radio,[lay-unrow]';
var container = $(this).find(UNROW);
if(
$(e.target).is(UNROW) ||
container[0] && $.contains(container[0], e.target)
){
return;
};
setRowEvent.call(this, 'row');
}).on('dblclick', 'tr', function(){ // 双击行
setRowEvent.call(this, 'rowDouble');

View File

@ -10,7 +10,6 @@ layui.define(['table'], function (exports) {
var form = layui.form;
var table = layui.table;
var hint = layui.hint();
var timer = {}; // 记录定时器 index
// api
var treeTable = {
@ -106,9 +105,13 @@ layui.define(['table'], function (exports) {
var updateOptions = function (id, options, reload) {
var that = getThisTable(id);
var thatOptionsTemp = $.extend(true, {} , that.getOptions(), options);
reload === 'reloadData' || (that.status = { // 用于记录一些状态信息
expand: {} // 折叠状态
});
var thatOptionsTemp = $.extend(true, {}, that.getOptions(), options);
var treeOptions = thatOptionsTemp.tree;
var childrenKey = treeOptions.customName.children;
var idKey = treeOptions.customName.id;
// 处理属性
delete options.hasNumberCol;
delete options.hasChecboxCol;
@ -141,6 +144,10 @@ layui.define(['table'], function (exports) {
if (treeOptions.data.isSimpleData && !treeOptions.async.enable) { // 异步加载和 isSimpleData 不应该一起使用
retData[dataName] = that.flatToTree(retData[dataName]);
}
// 处理节点状态
updateStatus(retData[dataName], function (item) {
item[LAY_EXPAND] = that.status.expand[item[idKey]]
}, childrenKey);
if (parseDataThat.autoSort && parseDataThat.initSort && parseDataThat.initSort.type) {
layui.sort(retData[dataName], parseDataThat.initSort.field, parseDataThat.initSort.type === 'desc', true)
@ -221,6 +228,7 @@ layui.define(['table'], function (exports) {
name: "name", // 节点数据保存节点名称的属性名称
id: "id", // 唯一标识的属性名称
pid: "parentId", // 父节点唯一标识的属性名称
icon: "icon", // 图标的属性名称
},
view: {
indent: 14, // 层级缩进量
@ -270,14 +278,18 @@ layui.define(['table'], function (exports) {
// 创建一个空的 nodes 对象,用于保存所有的节点
var nodes = {};
// 遍历所有节点,将其加入 nodes 对象中
var idTemp = '';
layui.each(flatArr, function (index, item) {
nodes[item[idKey]] = $.extend({}, item);
nodes[item[idKey]][childrenKey] = [];
idTemp = idKey + item[idKey];
nodes[idTemp] = $.extend({}, item);
nodes[idTemp][childrenKey] = [];
})
// 遍历所有节点,将其父子关系加入 nodes 对象
var pidTemp = '';
layui.each(nodes, function (index, item) {
if (item[pIdKey] && nodes[item[pIdKey]]) {
nodes[item[pIdKey]][childrenKey].push(item);
pidTemp = idKey + item[pIdKey];
if (pidTemp && nodes[pidTemp]) {
nodes[pidTemp][childrenKey].push(item);
}
})
// 返回顶层节点
@ -319,6 +331,95 @@ layui.define(['table'], function (exports) {
return flat;
}
// 通过当前行数据返回 treeNode 信息
Class.prototype.getTreeNode = function (data) {
var that = this;
if (!data) {
return hint.error('找不到节点数据');
}
var options = that.getOptions();
var treeOptions = options.tree;
var tableId = options.id;
var customName = treeOptions.customName;
var treeNode = {
data: data,
dataIndex: data[LAY_DATA_INDEX],
getParentNode: function () {
return that.getNodeByIndex(data[LAY_PARENT_INDEX])
},
}
// 带上一些常用的方法
return treeNode;
}
// 通过 index 返回节点信息
Class.prototype.getNodeByIndex = function (index) {
var that = this;
var treeNodeData = that.getNodeDataByIndex(index);
if (!treeNodeData) {
return hint.error('找不到节点数据');
}
var options = that.getOptions();
var treeOptions = options.tree;
var customName = treeOptions.customName;
var parentKey = customName.parent;
var tableId = options.id;
var treeNode = {
data: treeNodeData,
dataIndex: treeNodeData[LAY_DATA_INDEX],
getParentNode: function () {
return that.getNodeByIndex(treeNodeData[LAY_PARENT_INDEX])
},
update: function (data) {
return treeTable.updateNode(tableId, index, data)
},
remove: function () {
return treeTable.removeNode(tableId, index)
},
expand: function (opts) {
return treeTable.expandNode(tableId, $.extend({}, opts, {
index: index
}))
},
setChecked: function (opts) {
return treeTable.setRowChecked(tableId, $.extend({}, opts, {
index: index
}))
}
};
treeNode.dataIndex = index;
return treeNode;
}
// 通过 id 获取节点信息
Class.prototype.getNodeById = function (id) {
var that = this;
var options = that.getOptions();
var treeOptions = options.tree;
var customName = treeOptions.customName;
var idKey = customName.id;
// 通过 id 拿到数据的 dataIndex
var dataIndex = '';
var tableDataFlat = treeTable.getData(options.id, true);
layui.each(tableDataFlat, function (i1, item1) {
if (item1[idKey] === id) {
dataIndex = item1[LAY_DATA_INDEX];
return true;
}
})
if (!dataIndex) {
return;
}
// 用index
return that.getNodeByIndex(dataIndex);
}
// 通过index获取节点数据
Class.prototype.getNodeDataByIndex = function (index, clone, newValue) {
var that = this;
@ -344,9 +445,6 @@ layui.define(['table'], function (exports) {
// 删除
if (tableCache) {
// 同步cache
// tableCache.splice(tableCache.findIndex(function (value) {
// return value[LAY_DATA_INDEX] === index;
// }), 1);
layui.each(tableCache, function (i1, item1) {
if (item1[LAY_DATA_INDEX] === index) {
tableCache.splice(i1, 1);
@ -414,7 +512,9 @@ layui.define(['table'], function (exports) {
var debounceFn = (function () {
var fn = {};
return function (tableId, func, wait) {
fn[tableId] = fn[tableId] || layui.debounce(func, wait);
if (!fn[tableId]) {
fn[tableId] = layui.debounce(func, wait);
}
return fn[tableId];
}
})()
@ -439,9 +539,6 @@ layui.define(['table'], function (exports) {
var isToggle = layui.type(expandFlag) !== 'boolean';
var trExpand = isToggle ? !trData[LAY_EXPAND] : expandFlag;
var retValue = trData[isParentKey] ? trExpand : null;
if (retValue === null) {
return retValue;
}
if (callbackFlag && trExpand != trData[LAY_EXPAND] && (!trData[LAY_ASYNC_STATUS] || trData[LAY_ASYNC_STATUS] === 'local')) {
var beforeExpand = treeOptions.callback.beforeExpand;
@ -461,9 +558,15 @@ layui.define(['table'], function (exports) {
flexIconElem.html(trExpand ? treeOptions.view.flexIconOpen : treeOptions.view.flexIconClose)
trData[isParentKey] && flexIconElem.css('visibility', 'visible');
// 处理节点图标
treeOptions.view.showIcon && trsElem.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)')
treeOptions.view.showIcon && trsElem
.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)')
.html(trExpand ? treeOptions.view.iconOpen : treeOptions.view.iconClose);
treeTableThat.status.expand[trData[customName.id]] = trData[LAY_EXPAND] = trExpand;
if (retValue === null) {
return retValue;
}
var childNodes = trData[customName.children] || [];
// 处理子节点展示与否
if (trExpand) {
@ -472,7 +575,6 @@ layui.define(['table'], function (exports) {
trsElem.nextAll(childNodes.map(function (value, index, array) {
return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'
}).join(',')).removeClass(HIDE);
trData[LAY_EXPAND] = trExpand;
layui.each(childNodes, function (i1, item1) {
if (!item1[isParentKey]) {
return;
@ -500,9 +602,24 @@ layui.define(['table'], function (exports) {
} else {
var asyncSetting = treeOptions.async || {};
var asyncUrl = asyncSetting.url || options.url;
// 提供一个能支持用户在获取子数据转换调用的回调,这样让子节点数据获取更加灵活 todo
if (asyncSetting.enable && trData[isParentKey] && asyncUrl && !trData[LAY_ASYNC_STATUS]) {
if (asyncSetting.enable && trData[isParentKey] && !trData[LAY_ASYNC_STATUS]) {
trData[LAY_ASYNC_STATUS] = 'loading';
flexIconElem.html('<i class="layui-icon layui-icon-loading layui-anim layui-anim-loop layui-anim-rotate"></i>');
// 异步获取子节点数据成功之后处理方法
var asyncSuccessFn = function (data) {
trData[LAY_ASYNC_STATUS] = 'success';
trData[customName.children] = data;
treeTableThat.initData(trData[customName.children], trData[LAY_DATA_INDEX])
expandNode(treeNode, true, isToggle ? false : sonSign, focus, callbackFlag);
}
var format = asyncSetting.format; // 自定义数据返回方法
if (layui.type(format) === 'function') {
format(trData, options, asyncSuccessFn);
return retValue;
}
var params = {};
// 参数
var data = $.extend(params, asyncSetting.where || options.where);
@ -524,8 +641,6 @@ layui.define(['table'], function (exports) {
var asyncParseData = asyncSetting.parseData || options.parseData;
var asyncResponse = asyncSetting.response || options.response;
// that.loading();
flexIconElem.html('<i class="layui-icon layui-icon-loading layui-anim layui-anim-loop layui-anim-rotate"></i>')
$.ajax({
type: asyncType || 'get',
url: asyncUrl,
@ -535,7 +650,6 @@ layui.define(['table'], function (exports) {
jsonpCallback: asyncJsonpCallback,
headers: asyncHeaders || {},
success: function (res) {
trData[LAY_ASYNC_STATUS] = 'success';
// 若有数据解析的回调,则获得其返回的数据
if (typeof asyncParseData === 'function') {
res = asyncParseData.call(options, res) || res;
@ -547,10 +661,8 @@ layui.define(['table'], function (exports) {
flexIconElem.html('<i class="layui-icon layui-icon-refresh"></i>');
// 事件
} else {
trData[customName.children] = res[asyncResponse.dataName];
treeTableThat.initData(trData[customName.children], trData[LAY_DATA_INDEX])
// 正常返回
expandNode(treeNode, true, isToggle ? false : sonSign, focus, callbackFlag);
asyncSuccessFn(res[asyncResponse.dataName]);
}
},
error: function (e, msg) {
@ -561,7 +673,6 @@ layui.define(['table'], function (exports) {
});
return retValue;
}
trData[LAY_EXPAND] = trExpand;
trExpanded = trData[LAY_HAS_EXPANDED] = true;
if (childNodes.length) {
// 判断是否需要排序
@ -608,9 +719,7 @@ layui.define(['table'], function (exports) {
tableViewElem.find(ELEM_FIXR).find('tbody tr[lay-data-index="' + dataIndex + '"]').after(str2Obj.trs_fixed_r);
// 初始化新增的节点中的内容
layui.each(str2Obj, function (key, item) {
treeTableThat.renderTreeTable(item, dataLevelNew);
})
treeTableThat.renderTreeTable(str2Obj.trs, dataLevelNew);
if (sonSign && !isToggle) { // 非状态切换的情况下
// 级联展开/关闭子节点
@ -627,7 +736,6 @@ layui.define(['table'], function (exports) {
}
}
} else {
trData[LAY_EXPAND] = trExpand;
// 关闭
if (sonSign && !isToggle) { // 非状态切换的情况下
layui.each(childNodes, function (i1, item1) {
@ -649,13 +757,15 @@ layui.define(['table'], function (exports) {
}).join(',')).addClass(HIDE);
}
}
debounceFn(tableId, function () {
debounceFn('resize-' + tableId, function () {
treeTable.resize(tableId);
}, 25)();
}, 0)();
if (callbackFlag && trData[LAY_ASYNC_STATUS] !== 'loading') {
var onExpand = treeOptions.callback.onExpand;
layui.type(onExpand) === 'function' && onExpand(tableId, trData, expandFlag);
layui.type(onExpand) === 'function' && onExpand(tableId, trData, trExpand);
}
return retValue;
@ -719,7 +829,9 @@ layui.define(['table'], function (exports) {
tableView.find('.layui-table-box tbody tr[data-level!="0"]').addClass(HIDE);
tableView.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconClose);
treeOptions.view.showIcon && tableView.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)').html(treeOptions.view.iconClose);
treeOptions.view.showIcon && tableView
.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)')
.html(treeOptions.view.iconClose);
} else {
var tableDataFlat = treeTable.getData(id, true);
// 展开所有
@ -766,15 +878,20 @@ layui.define(['table'], function (exports) {
tableView.find('tbody tr[data-level!="0"]').removeClass(HIDE);
// 处理节点的图标
tableView.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconOpen);
treeOptions.view.showIcon && tableView.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)').html(treeOptions.view.iconOpen);
treeOptions.view.showIcon && tableView
.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)')
.html(treeOptions.view.iconOpen);
} else {
// 如果有未打开过的父节点,将内容全部生成
// 如果有未打开过的父节点,将 tr 内容全部重新生成
that.updateStatus(null, function (d) {
if (d[isParentKey]) {
d[LAY_EXPAND] = true;
d[LAY_HAS_EXPANDED] = true;
}
}); // {LAY_EXPAND: true, LAY_HAS_EXPANDED: true});
});
if (options.initSort && options.initSort.type && (!options.url || options.autoSort)) {
return treeTable.sort(id);
}
var trAll = table.getTrHtml(id, tableDataFlat);
var trAllObj = {
@ -782,23 +899,17 @@ layui.define(['table'], function (exports) {
trs_fixed: $(trAll.trs_fixed.join('')),
trs_fixed_r: $(trAll.trs_fixed_r.join(''))
}
var props;
layui.each(tableDataFlat, function (dataIndex, dataItem) {
var dataLevel = dataItem[LAY_DATA_INDEX].split('-').length - 1;
trAllObj.trs.eq(dataIndex).attr({
props = {
'data-index': dataItem[LAY_DATA_INDEX],
'lay-data-index': dataItem[LAY_DATA_INDEX],
'data-level': dataLevel
})
trAllObj.trs_fixed.eq(dataIndex).attr({
'data-index': dataItem[LAY_DATA_INDEX],
'lay-data-index': dataItem[LAY_DATA_INDEX],
'data-level': dataLevel
})
trAllObj.trs_fixed_r.eq(dataIndex).attr({
'data-index': dataItem[LAY_DATA_INDEX],
'lay-data-index': dataItem[LAY_DATA_INDEX],
'data-level': dataLevel
})
};
trAllObj.trs.eq(dataIndex).attr(props)
trAllObj.trs_fixed.eq(dataIndex).attr(props)
trAllObj.trs_fixed_r.eq(dataIndex).attr(props)
})
layui.each(['main', 'fixed-l', 'fixed-r'], function (i, item) {
tableView.find('.layui-table-' + item + ' tbody').html(trAllObj[['trs', 'trs_fixed', 'trs_fixed_r'][i]]);
@ -813,7 +924,7 @@ layui.define(['table'], function (exports) {
var that = this;
var options = that.getOptions();
var tableViewElem = options.elem.next();
tableViewElem.addClass(TABLE_TREE);
!tableViewElem.hasClass(TABLE_TREE) && tableViewElem.addClass(TABLE_TREE);
var tableId = options.id;
var treeOptions = options.tree || {};
var treeOptionsData = treeOptions.data || {};
@ -836,7 +947,7 @@ layui.define(['table'], function (exports) {
})
}
var dataExpand = {}; // 记录需要展开的数据
var dataExpand = null; // 记录需要展开的数据
var nameKey = customName.name;
var indent = treeOptionsView.indent || 14;
layui.each(tableView.find('td[data-field="' + nameKey + '"]'), function (index, item) {
@ -846,21 +957,26 @@ layui.define(['table'], function (exports) {
if (itemCell.hasClass('layui-table-tree-item')) {
return;
}
itemCell.addClass('layui-table-tree-item');
var trIndex = trElem.attr('lay-data-index');
if (!trIndex) { // 排除在统计行中的节点
return;
}
trElem = tableViewElem.find('tr[lay-data-index="' + trIndex + '"]');
var trData = treeTableThat.getNodeDataByIndex(trIndex);
if (trData[LAY_EXPAND]) {
// 需要展开
dataExpand = dataExpand || {};
dataExpand[trIndex] = true;
}
if (trData[LAY_CHECKBOX_HALF]) {
trElem.find('input[type="checkbox"][name="layTableCheckbox"]').prop('indeterminate', true);
}
var tableCellElem = item.find('div.layui-table-cell');
var htmlTemp = tableCellElem.html();
var flexIconElem = item.find('div.layui-table-cell')
var htmlTemp = itemCell.html();
itemCell = trElem.find('td[data-field="' + nameKey + '"]>div.layui-table-cell');
itemCell.addClass('layui-table-tree-item');
var flexIconElem = itemCell
.html(['<div class="layui-inline layui-table-tree-flexIcon" ',
'style="',
'margin-left: ' + (indent * trElem.attr('data-level')) + 'px;',
@ -869,10 +985,10 @@ layui.define(['table'], function (exports) {
trData[LAY_EXPAND] ? treeOptionsView.flexIconOpen : treeOptionsView.flexIconClose, // 折叠图标
'</div>',
treeOptionsView.showIcon ? '<div class="layui-inline layui-table-tree-nodeIcon' +
((trData.icon || treeOptionsView.icon) ? ' layui-table-tree-iconCustom' : '') +
((trData[customName.icon] || treeOptionsView.icon) ? ' layui-table-tree-iconCustom' : '') +
(trData[isParentKey] ? '' : ' layui-table-tree-iconLeaf') +
'">' +
(trData.icon || treeOptionsView.icon ||
(trData[customName.icon] || treeOptionsView.icon ||
(trData[isParentKey] ?
(trData[LAY_EXPAND] ? treeOptionsView.iconOpen : treeOptionsView.iconClose) :
treeOptionsView.iconLeaf) ||
@ -890,14 +1006,18 @@ layui.define(['table'], function (exports) {
});
// 当前层的数据看看是否需要展开
sonSign !== false && layui.each(dataExpand, function (index, item) {
var trDefaultExpand = tableViewElem.find('tr[lay-data-index="' + index + '"]');
trDefaultExpand.find('.layui-table-tree-flexIcon').html(treeOptionsView.flexIconOpen);
expandNode({trElem: trDefaultExpand.first()}, true);
});
options.hasNumberCol && that.formatNumber(tableId);
form.render(null, tableFilterId);
if (sonSign !== false && dataExpand) {
layui.each(dataExpand, function (index, item) {
var trDefaultExpand = tableViewElem.find('tr[lay-data-index="' + index + '"]');
trDefaultExpand.find('.layui-table-tree-flexIcon').html(treeOptionsView.flexIconOpen);
expandNode({trElem: trDefaultExpand.first()}, true);
});
} else {
debounceFn('renderTreeTable-' + tableId, function () {
options.hasNumberCol && formatNumber(that);
form.render(null, tableFilterId);
}, 0)();
}
}
var formatNumber = function (that) {
@ -905,24 +1025,18 @@ layui.define(['table'], function (exports) {
var tableViewElem = options.elem.next();
var num = 0;
var trMain = tableViewElem.find('.layui-table-main tbody tr');
var trFixedL = tableViewElem.find('.layui-table-fixed-l tbody tr');
var trFixedR = tableViewElem.find('.layui-table-fixed-r tbody tr');
layui.each(that.treeToFlat(table.cache[options.id]), function (i1, item1) {
if (layui.isArray(item1)) {
return;
}
var itemData = that.getNodeDataByIndex(item1[LAY_DATA_INDEX]);
itemData['LAY_NUM'] = ++num;
tableViewElem.find('tr[lay-data-index="' + item1[LAY_DATA_INDEX] + '"] .laytable-cell-numbers').html(itemData['LAY_NUM']);
trMain.eq(i1).find('.laytable-cell-numbers').html(num);
trFixedL.eq(i1).find('.laytable-cell-numbers').html(num);
trFixedR.eq(i1).find('.laytable-cell-numbers').html(num);
})
}
Class.prototype.formatNumber = function (id) {
var that = this;
clearTimeout(id);
timer[id] = setTimeout(function () {
formatNumber(that);
}, 10)
}
// 树表渲染
Class.prototype.render = function (type) {
var that = this;
@ -943,7 +1057,7 @@ layui.define(['table'], function (exports) {
});
// 根据需要处理options中的一些参数
updateOptions(that.config.id, options, true);
updateOptions(that.config.id, options, type || true);
// 对参数进行深度或浅扩展
that.config = $.extend(deep, {}, that.config, options);
@ -1107,7 +1221,7 @@ layui.define(['table'], function (exports) {
var indexArr = [];
delNode = that.getNodeDataByIndex(layui.type(node) === 'string' ? node : node[LAY_DATA_INDEX], false, 'delete');
var nodeP = that.getNodeDataByIndex(delNode[LAY_PARENT_INDEX]);
that.updateCheckStatus(nodeP, true);
that.updateCheckStatus(nodeP);
var delNodesFlat = that.treeToFlat([delNode], delNode[treeOptions.customName.pid], delNode[LAY_PARENT_INDEX]);
layui.each(delNodesFlat, function (i2, item2) {
indexArr.push('tr[lay-data-index="' + item2[LAY_DATA_INDEX] + '"]');
@ -1130,7 +1244,7 @@ layui.define(['table'], function (exports) {
layui.each(table.cache[id], function (i4, item4) {
tableView.find('tr[data-level="0"][lay-data-index="' + item4[LAY_DATA_INDEX] + '"]').attr('data-index', i4);
})
options.hasNumberCol && that.formatNumber(id);
options.hasNumberCol && formatNumber(that);
}
/**
@ -1189,22 +1303,16 @@ layui.define(['table'], function (exports) {
trs_fixed_r: $(newNodesHtml.trs_fixed_r.join(''))
}
var attrs = {};
layui.each(newNodes, function (newNodeIndex, newNodeItem) {
newNodesHtmlObj.trs.eq(newNodeIndex).attr({
attrs = {
'data-index': newNodeItem[LAY_DATA_INDEX],
'lay-data-index': newNodeItem[LAY_DATA_INDEX],
'data-level': '0'
})
newNodesHtmlObj.trs_fixed.eq(newNodeIndex).attr({
'data-index': newNodeItem[LAY_DATA_INDEX],
'lay-data-index': newNodeItem[LAY_DATA_INDEX],
'data-level': '0'
})
newNodesHtmlObj.trs_fixed_r.eq(newNodeIndex).attr({
'data-index': newNodeItem[LAY_DATA_INDEX],
'lay-data-index': newNodeItem[LAY_DATA_INDEX],
'data-level': '0'
})
};
newNodesHtmlObj.trs.eq(newNodeIndex).attr(attrs)
newNodesHtmlObj.trs_fixed.eq(newNodeIndex).attr(attrs)
newNodesHtmlObj.trs_fixed_r.eq(newNodeIndex).attr(attrs)
})
var trIndexPrev = parseInt(newNodes[0][LAY_DATA_INDEX]) - 1;
var tableViewElemMAIN = tableViewElem.find(ELEM_MAIN);
@ -1267,7 +1375,7 @@ layui.define(['table'], function (exports) {
parentNode[LAY_ASYNC_STATUS] = 'local'; // 转为本地数据应该规定异步加载子节点的时候addNodes的规则
expandNode({trElem: tableViewElem.find('tr[lay-data-index="' + parentIndex + '"]')}, true)
}
that.updateCheckStatus(parentNode, true);
that.updateCheckStatus(parentNode);
treeTable.resize(id);
if (focus) {
// 滚动到第一个新增的节点
@ -1277,19 +1385,20 @@ layui.define(['table'], function (exports) {
}
// 获取表格选中状态
treeTable.checkStatus = function (id) {
treeTable.checkStatus = function (id, includeHalfCheck) {
var that = getThisTable(id);
if(!that) return;
if (!that) return;
var checkName = table.config.checkName;
// 需要区分单双选
var tableData = treeTable.getData(id, true);
var checkedData = tableData.filter(function (value, index, array) {
return value[table.config.checkName];
return value[checkName] || (includeHalfCheck && value[LAY_CHECKBOX_HALF]);
});
var isAll = true;
layui.each(table.cache[id], function (i1, item1) {
if (!item1[table.config.checkName]) {
if (!item1[checkName]) {
isAll = false;
return true;
}
@ -1402,7 +1511,7 @@ layui.define(['table'], function (exports) {
// 如有必要更新父节点们的状态
if (dataP) {
var trsP = that.updateParentCheckStatus(dataP, checked);
var trsP = that.updateParentCheckStatus(dataP, layui.type(checked) === 'boolean' ? checked : null);
layui.each(trsP, function (indexP, itemP) {
form.render(tableView.find('tr[lay-data-index="' + itemP[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)').prop({
checked: itemP[checkName],
@ -1442,7 +1551,7 @@ layui.define(['table'], function (exports) {
var dataRet = [];
dataP[LAY_CHECKBOX_HALF] = false; // 先设置为非半选,是否为半选又下面逻辑判断
if (checked) {
if (checked === true) {
// 为真需要判断子节点的情况
if (!dataP[childrenKey].length) {
checked = false;
@ -1455,7 +1564,7 @@ layui.define(['table'], function (exports) {
}
});
}
} else {
} else if (checked === false) {
// 判断是否为半选
layui.each(dataP[childrenKey], function (index, item) {
if (item[checkName] || item[LAY_CHECKBOX_HALF]) { // 只要有一个子节点为选中或者半选状态
@ -1463,6 +1572,17 @@ layui.define(['table'], function (exports) {
return true;
}
});
} else {
// 状态不确定的情况下根据子节点的信息
checked = false;
var checkedNum = 0;
layui.each(dataP[childrenKey], function (index, item) {
if (item[checkName]) {
checkedNum++;
}
});
checked = dataP[childrenKey].length ? dataP[childrenKey].length === checkedNum : dataP[checkName]; // 如果没有子节点保留原来的状态;
dataP[LAY_CHECKBOX_HALF] = checked ? false : checkedNum > 0;
}
dataP[checkName] = checked;
dataRet.push($.extend({}, dataP));
@ -1572,13 +1692,13 @@ layui.define(['table'], function (exports) {
}
})
/**
* 设置行选中状态
* @param {String} id 树表id
* @param {Object|String} index 节点下标
* @param {Boolean} checked 选中或取消
* @param {Boolean} [callbackFlag] 是否触发事件回调
* @param {Object} opts
* @param {Object|String} opts.index 节点下标
* @param {Boolean} opts.checked 选中或取消
* @param {Boolean} [opts.callbackFlag] 是否触发事件回调
* */
treeTable.setRowChecked = function (id, opts) {
var that = getThisTable(id);
@ -1630,14 +1750,93 @@ layui.define(['table'], function (exports) {
* @return {Array} 表格数据
* */
treeTable.getData = function (id, isSimpleData) {
var that = getThisTable(id);
if (!that) return;
var tableData = [];
layui.each($.extend(true, [], table.cache[id] || []), function (index, item) {
// 遍历排除掉临时的数据
tableData.push(item);
})
return isSimpleData ? getThisTable(id).treeToFlat(tableData) : tableData;
return isSimpleData ? that.treeToFlat(tableData) : tableData;
}
/**
* 重新加载子节点
* @param {String} id 表格id
* @param {String} dataIndex 父节点的dataIndex
* */
treeTable.reAsync = function (id, dataIndex) {
var that = getThisTable(id);
if (!that) {
return;
}
var options = that.getOptions();
var treeOptions = options.tree;
if (!treeOptions.async || !treeOptions.async.enable) {
return;
}
var dataP = that.getNodeDataByIndex(dataIndex);
if (!dataP) {
return;
}
dataP[LAY_HAS_EXPANDED] = false;
dataP[LAY_EXPAND] = false;
dataP[LAY_ASYNC_STATUS] = false;
layui.each(that.treeToFlat(dataP[treeOptions.customName.children]).reverse(), function (i1, item1) {
treeTable.removeNode(id, item1[LAY_DATA_INDEX]);
})
// 重新展开
treeTable.expandNode(id, {
index: dataIndex,
expandFlag: true,
callbackFlag: true,
})
}
/**
* 通过数据id获取节点对象
* */
treeTable.getNodeById = function (id, dataId) {
var that = getThisTable(id);
if (!that) return;
return that.getNodeById(dataId);
}
/**
* 根据自定义规则搜索节点数据
* @param {String} id 树表id
* @param {Function} filter 自定义过滤器函数
* @param {Object} [opts]
* @param {Boolean} [opts.isSingle] 是否只找到第一个
* @param {Object} [opts.parentNode] 在指定在某个父节点下的子节点中搜索
* @return {Object} 节点对象
* */
treeTable.getNodesByFilter = function (id, filter, opts) {
var that = getThisTable(id);
if (!that) return;
var options = that.getOptions();
opts = opts || {};
var isSingle = opts.isSingle;
var parentNode = opts.parentNode;
var dataP = parentNode && parentNode.data;
// dataP = dataP || table.cache[id];
var nodes = that.treeToFlat(dataP ? (dataP[options.tree.customName.children] || []) : table.cache[id]).filter(filter);
var nodesResult = [];
layui.each(nodes, function (i1, item1) {
nodesResult.push(that.getNodeByIndex(item1[LAY_DATA_INDEX]));
if (isSingle) {
return true;
}
});
return nodesResult;
}
// 记录所有实例
thisTreeTable.that = {}; // 记录所有实例对象
// thisTreeTable.config = {}; // 记录所有实例配置项

View File

@ -226,7 +226,10 @@ layui.define(['lay','layer'], function(exports){
//异常回调
,error: function(e){
failed++;
that.msg('Request URL is abnormal: '+ (e.statusText || 'error'));
that.msg([
'Upload failed, please try again.',
'status: '+ (e.status || '') +' - '+ (e.statusText || 'error')
].join('<br>'));
error(index);
allDone();
}
@ -395,7 +398,7 @@ layui.define(['lay','layer'], function(exports){
break;
default: //图片文件
layui.each(value, function(i, item){
if(!RegExp('.\\.('+ (exts || 'jpg|png|gif|bmp|jpeg') +')$', 'i').test(escape(item))){
if(!RegExp('.\\.('+ (exts || 'jpg|png|gif|bmp|jpeg|svg') +')$', 'i').test(escape(item))){
return check = true;
}
});

View File

@ -64,7 +64,7 @@ layui.define('jquery', function(exports){
// 设置 bar 相关属性
elemBar.addClass(item.icon).attr({
'lay-type': item.type,
'style': item.style || ('background-color: '+ options.bgcolor)
'style': item.style || ('background-color: '+ options.bgcolor || '')
}).html(item.content);
// bar 点击事件