release v2.8.18-beta (#1391)

release v2.8.18-beta
pull/1400/head v2.8.18-beta
贤心 2023-10-07 17:23:59 +08:00 committed by GitHub
commit 5ba2dfa5d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 812 additions and 427 deletions

View File

@ -1,6 +1,5 @@
name: 😇 问题反馈
description: 使用 Layui 过程中遇到的 Bug、异常或其他困惑。
title: ""
body:
- type: markdown
attributes:

View File

@ -1,5 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 📄 阅读文档
- name: 📄 官方文档
url: https://layui.dev/
about: 建议你在创建 Issue 之前,仔细查阅 Layui 开发文档,以便对其有更深入的了解,和更好地分析问题。
about: 建议你在创建 Issue 之前,仔细查阅 Layui 开发文档,以便对其有更深入的了解,和更好地分析问题。

66
.github/ISSUE_TEMPLATE/bug.yml vendored Normal file
View File

@ -0,0 +1,66 @@
name: 😇 问题反馈
description: 使用 Layui 过程中遇到的 Bug、异常或其他困惑。
body:
- type: markdown
attributes:
value: |
**系统提示**:此处只接受 Layui 相关技术问题,其他如 layuiAdmin 或 LayIM 等主题相关问题请勿在此反馈。
- type: checkboxes
attributes:
label: 议题条件
options:
- label: 我确认已查看官方使用文档:**https://layui.dev** ,但没有找到相关解决方案。
required: true
- label: 我确认已在 **Issues** 中搜索过类似的问题,但没有找到相关解决方案。
required: true
- type: input
attributes:
label: 版本号
placeholder: 请提供您所使用的 Layui 版本号
validations:
required: true
- type: input
attributes:
label: 浏览器
placeholder: Chrome 116.0.5845.111(正式版本) 64 位)
validations:
required: true
- type: dropdown
id: type
attributes:
label: 问题类型
options:
- 疑是 BUG
- 报错提示
- 功能困惑
validations:
required: true
- type: textarea
attributes:
label: 问题描述
placeholder: 请提供详细的问题描述和操作步骤等信息,以便我们也能够更轻松地将问题复现。
validations:
required: true
- type: textarea
attributes:
label: 业务代码
description: 直接粘贴问题对应的 `HTML,CSS,JavaScript` 等代码到下面的文本框,无需书写 `Markdown`
placeholder: 请提供与该问题对应的业务代码片段,以便我们更好地排查问题。
render: auto
validations:
required: true
- type: textarea
attributes:
label: 截图补充
placeholder: 如上述仍然无法准确地表述问题,可提供必要的截图(可直接粘贴上传)
- type: input
attributes:
label: 演示地址
description: 若能提供 Stackblitz, CodePen 或自主搭建的页面演示地址,将更有助于解决问题
placeholder: URL
- type: checkboxes
attributes:
label: 友好承诺
options:
- label: 我承诺将本着相互尊重、理解和友善的态度进行交流,共同维护 Layui 良好的社区氛围。
required: true

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 📄 官方文档
url: https://layui.dev/
about: 建议您在创建 Issue 之前,仔细查阅 Layui 开发文档,以便对其有更深入的了解,和更好地分析问题。

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

@ -22,6 +22,16 @@
</td>
<td>string/DOM</td>
<td>-</td>
</tr>
<tr>
<td>code <sup>2.8.18+</sup></td>
<td>
设置原始 code 值,默认取目标元素中的内容
</td>
<td>string</td>
<td>-</td>
</tr>
<tr>
@ -302,12 +312,14 @@ Code 文字是否自动换行
<td>highlighter <sup>2.8.17+</sup></td>
<td>
指定语法高亮器,可选值:
设置语法高亮器,可选值:
- `hljs` : 指定 `highlight.js`
- `prism` : 指定 `prism.js`
- `shiki` : 指定 `shiki.js`
注:对应的语法高亮器 JS 库和相关主题 CSS 需自主引入,该属性仅用于内部适配。
</td>
<td>string</td>
<td>-</td>

View File

@ -3,6 +3,8 @@
<hr>
<input type="password" name="password" lay-verify="password" placeholder="密码" class="layui-input">
<hr>
<input type="text" name="motto" lay-verify="motto" placeholder="座右铭" class="layui-input">
<hr>
<button class="layui-btn" lay-submit lay-filter="demo-verify">提交</button>
</form>
@ -11,25 +13,33 @@
layui.use(function(){
var form = layui.form;
// 自定义验证规则,如下以验证用户名和密码为例
// 自定义验证规则
form.verify({
// 参数 value 为表单的值;参数 item 为表单元素
username: function(value, item){
if(!new RegExp("^[a-zA-Z0-9_\u4e00-\u9fa5\\s·]+$").test(value)){
// 验证用户名,且为必填项
username: function(value, elem){
if (!new RegExp("^[a-zA-Z0-9_\u4e00-\u9fa5\\s·]+$").test(value)) {
return '用户名不能有特殊字符';
}
if(/(^_)|(__)|(_+$)/.test(value)) return '用户名首尾不能出现 _ 下划线';
if(/^\d+$/.test(value)) return '用户名不能全为数字';
// 若不想自动弹出默认提示框,可返回 true这时可通过其他提示方式替代v2.5.7 新增)
if(value === 'xxx'){
alert('用户名不能为敏感词');
return true;
if (/(^_)|(__)|(_+$)/.test(value)) {
return '用户名首尾不能出现下划线';
}
if (/^\d+$/.test(value)) {
return '用户名不能全为数字';
}
},
password: function(value) {
if (!/^[\S]{6,12}$/.test(value)) {
return '密码必须为 6 到 12 位的非空字符';
// 验证密码,且为必填项
password: function(value, elem) {
if (!/^[\S]{6,16}$/.test(value)) {
return '密码必须为 6 到 16 位的非空字符';
}
},
// 验证座右铭,且为非必填项
motto: function(value, elem) {
if (!value) return; // 非必填
// 自定义规则
if (!new RegExp("^[a-zA-Z0-9_\u4e00-\u9fa5\\s·]+$").test(value)) {
return '座右铭不能有特殊字符';
}
}
});

View File

@ -207,18 +207,18 @@ layui.use('form', function(){
<h2 id="lay-verify" lay-toc="{hot: true, level: 2}">验证</h2>
Layui 对表单做了相对巧妙的支持,只需在表单元素上设置 `lay-verify=""` 属性值即可指定验证规则,如:
Layui 对表单验证做了巧妙的支持,只需在表单元素上设置 `lay-verify=""` 属性值即可指定验证规则,如:
```
<div class="layui-form">
<input type="text" lay-verify="required">
<input type="text" lay-verify="email">
<input type="text" lay-verify="required|phone|number">
<input type="text" lay-verify="required" placeholder="必填项">
<input type="text" lay-verify="email" placeholder="非必填项,但若有值则验证邮箱格式">
<input type="text" lay-verify="required|number" placeholder="必填项,并验证数字格式">
<button class="layui-btn" lay-submit>提交</button>
</div>
```
其中,`lay-verify` 属性的内置规则值可参考上文的:[#属性介绍](#attr)。 当表单提交时,会自动触发验证。
注:上述代码指定的均为内置的验证规则,具体可参考:[#属性介绍](#attr)
<h3 id="verify" lay-toc="{level: 3, title: '定义验证规则'}" class="ws-bold">自定义验证规则</h3>
@ -226,7 +226,50 @@ Layui 对表单做了相对巧妙的支持,只需在表单元素上设置 `lay
- 参数 `obj` 是一个对象,用于定义验证规则的集合。
当内置的验证规则无法满足业务需求时,我们可以通过该方法自定义验证规则。如:
除了内置的验证规则外form 还允许自定义验证规则,规则以函数命名,返回的参数如下:
```
// 自定义验证规则
form.verify({
rule: function(value, elem) {
console.log(value); // 当前进入验证的表单项的值
console.log(elem); // 当前进入验证的表单项的 DOM 元素
}
});
```
在自定义规则中,可根据规则函数返回的 value 自行判断是否必填,如:
```
form.verify({
// 必填项
rule1: function(value, elem) {
// 自定义规则
if (value.length < 6) {
return '不能小于 6 个字符';
}
},
// 非必填项,只有当值填写时才验证自定义规则
rule2: function(value, elem) {
if (!value) return; // 若值未填写,不进行后续规则验证
// 自定义规则
if (/^[A-Z]/.test(value)) {
return '必须用大写字符开头';
}
},
// 自定义提示方式
rule3: function(value, elem) {
// 自定义规则和自定义提示方式
if(value === 'xxx'){
alert('用户名不能为敏感词'); // 此处以系统自带的 alert 提示方式为例
return true; // 返回 true 即可阻止 form 默认的提示风格
}
}
});
```
以下是一个自定义验证规则的示例:
<pre class="layui-code" lay-options="{preview: true, codeStyle: 'height: 508px;', done: function(obj){
obj.render()
@ -239,7 +282,6 @@ Layui 对表单做了相对巧妙的支持,只需在表单元素上设置 `lay
更多「自定义验证规则」示例参考:
> - <a href="https://gitee.com/layui/layui/issues/I5HC2L#note_11673264_link" target="_blank">将 form 提示语显示在表单项旁边,并在提交时批量触发验证</a>
> - <a href="https://gitee.com/layui/layui/issues/I42C7I#note_12020414_link" target="_blank">重置 form 内置验证规则,让其:当非空值才进行验证;加了 required 时才验证非空</a>
<h3 id="validate" lay-toc="{level: 3}" class="ws-bold">主动触发验证 <sup>2.7+</sup></h3>

View File

@ -1183,36 +1183,33 @@ toc: true
layui.use(function(){
var $ = layui.jquery;
var layer = layui.layer;
var lay = layui.lay;
var util = layui.util;
// click
$('.ws-docs-icon > div').on('click', function(e){
var elem = $(this);
var unicodeElem = elem.children('.docs-icon-code')
var classnameElem = elem.children('.docs-icon-fontclass')
var text = classnameElem.text();
var html = text;
$('.ws-docs-icon > div').on('click', function(){
var iconclass = $(this).find('.docs-icon-fontclass').text();
var copied = copy(iconclass);
if(copied){
layer.msg('已复制 '+ iconclass, {
icon: 1,
offset: '5%',
anim: 'slideDown',
isOutAnim: false
});
if ($(e.target).is(unicodeElem)) {
text = unicodeElem.text();
html = unicodeElem.html();
}
lay.clipboard.writeText({
text: text,
done: function() {
layer.msg('已复制 '+ html, {
icon: 1,
offset: '5%',
anim: 'slideDown',
isOutAnim: false
});
}
});
});
function copy(text){
var textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'absolute';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
var copied = false;
try{
copied = document.execCommand('copy');
}catch(err){
console.log('error', err);
}
textarea.remove();
return copied;
}
});
</script>
</textarea>

View File

@ -1,6 +1,6 @@
<h2 lay-toc="{id: 'examples', level: 2, hot: true}" class="layui-hide">在线测试</h2>
<pre class="layui-code" lay-options="{preview: true, text: {preview: '在线测试'}, layout: ['preview']}">
<pre class="layui-code" lay-options="{preview: true, text: {preview: '在线测试'}, copy: false, layout: ['preview']}">
<textarea>
{{- d.include("/layer/detail/run.md") }}
</textarea>

View File

@ -32,8 +32,8 @@ toc: true
| [layer.photos(options)](#photos) | 弹出 `page` 类型图片层。 |
| [layer.tab(options)](#tab) | 弹出 `page` 类型标签页层。 |
| 关闭 : | - |
| [layer.close(index)](#close) | 关闭对应的层,核心方法。 |
| [layer.closeAll(type)](#closeAll) | 关闭所有对应类型的层。 |
| [layer.close(index, callback)](#close) | 关闭对应的层,核心方法。 |
| [layer.closeAll(type, callback)](#closeAll) | 关闭所有对应类型的层。 |
| [layer.closeLast(type)](#closeLast) <sup>2.8+</sup> | 关闭最近打开的对应类型的层。 |
| 其他 : | - |
| [layer.config(options)](#config) | 全局配置默认属性。 |
@ -339,9 +339,10 @@ layer.tab({
<h2 id="close" lay-toc="{level: 2}">关闭弹层</h2>
`layer.close(index);`
`layer.close(index, callback);`
- 参数 `index` : 打开弹层时返回的唯一索引
- 参数 `callback` : 关闭弹层后的回调函数
该方法用于关闭对应的弹层。
@ -366,9 +367,10 @@ parent.layer.close(index); // 再执行关闭
<h2 id="closeAll" lay-pid="api" class="ws-anchor ws-bold">关闭所有层</h2>
`layer.closeAll(type);`
`layer.closeAll(type, callback);`
- 参数 `type` : 弹层的类型。可选值:`dialog,page,iframe,loading,tips`
- 参数 `callback` : 关闭弹层后的回调函数
该方法用于关闭所有同类型的弹层。

View File

@ -1,4 +1,4 @@
<pre class="layui-code" lay-options="{preview: true, layout: ['preview'], tools: ['full']}">
<pre class="layui-code" lay-options="{preview: true, layout: ['preview'], copy: false, tools: ['full'], addTools: null}">
<textarea>
{{!
<style>
@ -132,4 +132,4 @@ layui.use(function(){
</script>
!}}
</textarea>
</pre>
</pre>

View File

@ -319,7 +319,7 @@ treeTable.expandAll('test', false); // 关闭全部节点
| opts | 描述 | 类型 | 默认值 |
| --- | --- | -- | --- |
| index | 要设置选中状态的行下标或行数据 | number/object | - |
| checked | 选中状态。`true` 选中;`false` 取消选中;`null` 切换。 其中,`radio` 框,则不支持 `null`(切换)。 | boolean | - |
| checked | 选中状态。`true` 选中;`false` 取消选中;`null` 切换。 其中,`radio` 框,则不支持 `null`(切换)。 | boolean | - |
| callbackFlag | 是否触发事件,若为 `true`,则 `checked: false` 无效。其对应的事件跟 `table``radio,checkbox` 事件用法一样 | boolean | `false` |
```js
@ -364,4 +364,4 @@ treeTable.checkAllNodes('test', true); // 全选
## 贴士
> `treeTable` 基于 `table` 组件扩展而来,因此,熟练运用 `treeTable` 的前提是熟悉 `table` 组件。 亦可通过 `table` 提供的基础 `API` 操作 `treeTable` 组件,但 `treeTable` 无法操作 `table`
> `treeTable` 基于 `table` 组件扩展而来,因此,熟练运用 `treeTable` 的前提是熟悉 `table` 组件。 亦可通过 `table` 提供的基础 `API` 操作 `treeTable` 组件,但 `treeTable` 无法操作 `table`

View File

@ -15,7 +15,7 @@ layui.use(function(){
// 渲染
upload.render({
elem: '#ID-upload-demo-drag',
url: 'https://httpbin.org/post', // 此处用的是第三方的 http 请求演示,实际使用时改成您自己的上传接口即可。
url: '', // 实际使用时改成您自己的上传接口即可。
done: function(res){
layer.msg('上传成功');
$('#ID-upload-demo-preview').removeClass('layui-hide')
@ -24,4 +24,4 @@ layui.use(function(){
}
});
});
</script>
</script>

View File

@ -31,7 +31,7 @@ layui.use(function(){
var uploadListIns = upload.render({
elem: '#ID-upload-demo-files',
elemList: $('#ID-upload-demo-files-list'), // 列表元素对象
url: 'https://httpbin.org/post', // 此处用的是第三方的 http 请求演示,实际使用时改成您自己的上传接口即可。
url: '', // 实际使用时改成您自己的上传接口即可。
accept: 'file',
multiple: true,
number: 3,
@ -96,4 +96,4 @@ layui.use(function(){
}
});
});
</script>
</script>

View File

@ -32,7 +32,7 @@ layui.use(function(){
// 单图片上传
var uploadInst = upload.render({
elem: '#ID-upload-demo-btn',
url: 'https://httpbin.org/post', // 此处用的是第三方的 http 请求演示,实际使用时改成您自己的上传接口即可。
url: '', // 实际使用时改成您自己的上传接口即可。
before: function(obj){
// 预读本地文件示例不支持ie8
obj.preview(function(index, file, result){
@ -71,7 +71,7 @@ layui.use(function(){
// 多图片上传
upload.render({
elem: '#ID-upload-demo-btn-2',
url: 'https://httpbin.org/post', // 此处用的是第三方的 http 请求演示,实际使用时改成您自己的上传接口即可。
url: '', // 实际使用时改成您自己的上传接口即可。
multiple: true,
before: function(obj){
// 预读本地文件示例不支持ie8
@ -84,4 +84,4 @@ layui.use(function(){
// …
}
});
});
});

View File

@ -9,7 +9,7 @@ toc: true
<h2 id="examples" lay-toc="{hot: true, anchor: null}" style="margin-bottom: 0;">示例</h2>
以下示例的部分上传接口由第三方网站 `https://httpbin.org` 提供,它可以模拟各类 HTTP 请求。若未配置上传接口的,每次上传都会报「请求上传接口出现异常」的提示,这属于正常现象
以下示例均没有设置上传接口,因此每次上传都会报异常提示,这属于正常现象。实际使用时设置成您的真实上传接口即可
<div class="ws-docs-showcase"></div>

View File

@ -11,6 +11,43 @@ toc: true
> 导读:📑 [Layui 2.8 《升级指南》](/notes/2.8/upgrade-guide.html) · 📑 [Layui 新版文档站上线初衷](/notes/2.8/news.html)
<h2 id="2.8.18" class="ws-anchor">
2.8.18-beta
<span class="layui-badge-rim">2023-10-07</span>
</h2>
- #### form
- 新增 `input` 数字输入框组件的特定属性 `lay-precision`,用于设置数值精度 # 1375/I81SY4
- 优化 `input` 数字输入框组件的失去焦点对值的有效范围约束 # 1375/I7KU6V
- 优化 `input` 数字输入框组件当值达到临界点时加减按钮的禁用视觉效果 # 1375
- 优化 `input` 数字输入框当表单验证失败时的边框颜色 # 1371
- #### nav
- 新增 垂直导航菜单展开和收缩时的过渡动画 # 1384
- #### layer
- 优化 移动端定位 # 1376
- #### table
- 新增 `complete` 属性,当数据接口请求完成后执行,无论成功还是失败均会触发 # 1379
- #### treeTable
- 修复 treeTable 组件 treeTable.setRowChecked 未逐层展开上级节点的问题 # 1385/I84RUT
- #### upload
- 修复 `unified: true` 时的报错问题
- 优化 渲染入口逻辑,以解决因重复渲染导致的若干问题
- 优化 实例的 `reload` 方法,可更好地进行完整重载
- #### laydate
- 优化 开启 `rangeLinked` 属性后,点击目标元素可重新渲染的问题
- #### carousel
- 优化 轮播切换时的动画效果 # 1378/I82STP
- #### rate / slider
- 优化 代码细节 # 1374
- #### code
- 新增 `code` 属性,用于设置原始 code 值,优先级高于目标元素中的内容
- 优化 若干小问题
### 下载: [layui-v2.8.18-beta.zip](https://gitee.com/layui/layui/attach_files/1545385/download)
---
<h2 id="2.8.17" class="ws-anchor">
2.8.17
<span class="layui-badge-rim">2023-09-11</span>

View File

@ -136,16 +136,20 @@ code line
</div>
</pre>
<pre class="layui-code" lay-options="{about: 'About info'}">
<pre class="layui-code" lay-options="{about: 'AboutInfo'}">
About
</pre>
<script src="../src/layui.js"></script>
<!-- 第三方语法高亮库 -->
<script src="https://cdn.staticfile.org/highlight.js/11.8.0/highlight.min.js"></script>
<script src="https://cdn.staticfile.org/prism/1.29.0/prism.min.js"></script>
<!-- layui -->
<script src="../src/layui.js"></script>
<script>
layui.use(['code', 'dropdown'], function(){
var dropdown = layui.dropdown;
var layer = layui.layer;
var $ = layui.$;
// return;
@ -173,6 +177,7 @@ layui.use(['code', 'dropdown'], function(){
};
});
// 创建实例
var codeInst = layui.code({
elem: '#test',
preview: true,
@ -183,12 +188,14 @@ layui.use(['code', 'dropdown'], function(){
// wordWrap: false, // 是否自动换行
lang: 'html',
highlighter: "hljs",
/*codeRender: function (code, opts) {
// code: '<div class="layui-btn">初始按钮</div>',
/*codeRender: function (code, opts) { // 初始高亮
layui.link(themeData[1].link, 'layui-code-theme');
return hljs.highlight(code, {language: opts.lang}).value;
},*/
tools: [
'full',
'window',
{
title: ['文字换行'],
type: 'form',
@ -244,19 +251,36 @@ layui.use(['code', 'dropdown'], function(){
}
});
}
},
{
title: ['编辑'],
type: 'edit',
event: function(obj) {
layer.prompt({
formType: 2,
value: obj.rawCode,
title: '编辑代码',
area: ['800px', '500px'],
maxlength: 9999999999
}, function(value, index) {
layer.close(index);
// 重载 code
codeInst.reloadCode({
code: value
});
});
}
}
]
});
// 仅重载 code
layui.debounce(function() {
codeInst.reloadCode({
codeRender: function(code, opts) {
layui.link(themeData[1].link, 'layui-code-theme');
return hljs.highlight(code, {language: opts.lang}).value;
}
});
}, 300)();
// 语法高亮重载
codeInst.reloadCode({
codeRender: function(code, opts) {
layui.link(themeData[1].link, 'layui-code-theme');
return hljs.highlight(code, {language: opts.lang}).value;
}
});
// 通用实例,根据元素属性定制化参数

View File

@ -6,12 +6,10 @@
<title>导航 - 常用元素 - layui</title>
<link rel="stylesheet" href="../src/css/layui.css">
<style>
body{padding: 16px;}
.demo-nav-tree>.layui-inline{vertical-align: top;}
</style>
</head>
<body>
<body class="layui-padding-3">
<ul class="layui-nav">
<li class="layui-nav-item"><a href="">最新活动</a></li>
@ -130,7 +128,7 @@
<div class="demo-nav-tree">
<div class="layui-inline">
<ul class="layui-nav layui-nav-tree" lay-filter="test">
<ul class="layui-nav layui-nav-tree" lay-accordion lay-filter="test">
<li class="layui-nav-item">
<a class="" href="javascript:;">产品</a>
<dl class="layui-nav-child">

View File

@ -17,7 +17,7 @@ body{padding: 50px 100px;}
<body>
<div class="layui-inline">
<input type="text" class="layui-input" id="test-first">
<input type="text" class="layui-input" id="test-first" placeholder="带遮罩">
</div>
<br>
@ -157,7 +157,7 @@ layui.use('laydate', function(laydate){
laydate.render({
elem: '#test-first',
min: 0,
shade: [0.1, '#ddd'],
shade: [0.1, '#000'],
//max: '2016-12-30',
done: function(){
console.log('done',arguments);

View File

@ -24,6 +24,7 @@
<button class="layui-btn" lay-on="test7">Prompt</button>
<button class="layui-btn" lay-on="test8">Tab</button>
<button class="layui-btn" lay-on="test9">Photo</button>
<button class="layui-btn" lay-on="test10">Drawer</button>
<button class="layui-btn" lay-on="testTime">自动关闭</button>
<a href="https://layui.dev/docs/2.8/layer/" target="_blank" class="layui-btn">更多例子</a>
</div>
@ -215,6 +216,19 @@ layui.use(['layer', 'util'], function(layer, util){
}
});
}
,test10: function(){
layer.open({
title:'drawer',
type: 1,
offset: 'b',
anim: 'slideUp', // 从下往上
area: ['100%', '160px'],
shade: 0.1,
shadeClose: true,
content: $('#test11111'),
maxmin: true,
});
}
});
// 相册层

View File

@ -5,11 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>树形表格 - layui</title>
<link rel="stylesheet" href="../src/css/layui.css">
<style>
body {padding: 32px;}
</style>
</head>
<body>
<body class="layui-padding-5">
<table class="layui-hide" id="test"></table>
@ -19,15 +16,26 @@
</div>
</script>
<script type="text/html" id="TPL-treeTable-demo-tools">
<div class="layui-btn-container">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="addChild">新增</a>
<a class="layui-btn layui-btn-xs" lay-event="more">更多 <i class="layui-icon layui-icon-down"></i></a>
</div>
</script>
<script src="../src/layui.js"></script>
<script>
layui.use(['treeTable'], function(){
layui.use(['treeTable', 'dropdown', 'layer'], function(){
var treeTable = layui.treeTable;
var dropdown = layui.dropdown;
var layer = layui.layer;
// 渲染
treeTable.render({
var inst = treeTable.render({
elem: '#test',
url: './json/treeTable/demo-1.json',
// data: createData(!0),
maxHeight: 'full-32',
toolbar: '#TPL-treeTable-demo',
tree: {
@ -48,7 +56,8 @@ layui.use(['treeTable'], function(){
{field: 'score', title: '评分', width: 80, sort: true},
{field: 'city', title: '城市', width: 150},
{field: 'description', title: '描述', minWidth: 200},
{field: 'createTime', title: '创建时间', width: 170, fixed: 'right'}
{field: 'createTime', title: '创建时间', width: 170},
{ fixed: "right", title: "操作", width: 190, align: "center", toolbar: "#TPL-treeTable-demo-tools"}
]],
page: true
});
@ -57,14 +66,82 @@ layui.use(['treeTable'], function(){
treeTable.on('row(test)', function (obj) {
console.log(obj);
});
// 表头工具栏工具事件
treeTable.on('toolbar('+ inst.config.id +')', function (obj) {
var config = obj.config;
var tableId = config.id;
var status = treeTable.checkStatus(tableId);
// 获取选中行
if (obj.event === "getChecked") {
if(!status.data.length) return layer.msg('无选中数据');
console.log(status);
layer.alert("当前数据选中已经输出到控制台,<br>您可按 F12 从控制台中查看结果。");
}
});
// 单元格工具事件
treeTable.on('tool('+ inst.config.id +')', function (obj) {
var layEvent = obj.event; // 获得 lay-event 对应的值
var trElem = obj.tr;
var trData = obj.data;
var tableId = obj.config.id;
if (layEvent === "detail") {
layer.msg("查看操作:" + trData.name);
} else if (layEvent === "addChild") {
var data = { id: Date.now(), name: "新节点" };
var newNode2 = treeTable.addNodes(tableId, {
parentIndex: trData["LAY_DATA_INDEX"],
index: -1,
data: data
});
} else if (layEvent === "more") {
// 下拉菜单
dropdown.render({
elem: this, // 触发事件的 DOM 对象
show: true, // 外部事件触发即显示
align: "right", // 右对齐弹出
data: [
{
title: "修改积分",
id: "edit"
},
{
title: "删除",
id: "del"
}
],
click: function (menudata) {
if (menudata.id === "del") {
console.log(trData);
layer.confirm("真的删除行么", function (index) {
obj.del(); // 等效如下
// treeTable.removeNode(tableId, trElem.attr('data-index'))
layer.close(index);
});
} else if (menudata.id === "edit") {
layer.prompt({
value: trData.experience,
title: "输入新的积分"
}, function (value, index) {
obj.update({ experience: value }); // 等效如下
// treeTable.updateNode(tableId, trElem.attr('data-index'), {experience: value});
layer.close(index);
});
}
}
});
}
});
});
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Mock.js/1.0.0/mock-min.js"></script>
<script src="https://cdn.staticfile.org/Mock.js/1.0.0/mock-min.js"></script>
<script>
// 生成模拟数据
const createData = () => {
const createData = (flat) => {
// 生成随机 ID 函数
const createId = (() => {
let nextId = 1
@ -78,6 +155,7 @@ const createData = () => {
createNode.bind(null, id, level + 1)
]
}).array : []
const isParent = 'isParent';
return {
id,
name: `User-${id}`,
@ -89,17 +167,22 @@ const createData = () => {
city: Mock.Random.city(),
description: '-',
createTime: Mock.mock('@datetime'),
parentId,
children,
isParent: !!children.length
[flat || 'parentId']: parentId,
[flat || 'children']: children,
[flat || isParent]: !!children.length
}
}
// 生成树
// 根节点
const rootNodes = Mock.mock({
'array|10-20': [
createNode
]
}).array
}).array;
if (flat) return rootNodes
// 生成树
const getTreeData = function (nodes) {
let result = []
nodes.forEach(node => {

View File

@ -8,12 +8,11 @@
<link rel="stylesheet" href="../src/css/layui.css">
<style>
body{padding: 50px 100px;}
.layui-upload-img{width: 92px; height: 92px; margin: 0 10px 10px 0;}
hr{margin: 30px 0;}
hr{margin: 32px 0;}
</style>
</head>
<body>
<body class="layui-padding-5">
<div class="layui-upload">
<button type="button" class="layui-btn" id="test1" name="123">上传图片</button>
@ -89,16 +88,20 @@ hr{margin: 30px 0;}
绑定原始文件域:<input type="file" name="file" id="test9">
<script src="../src/layui.js" src1="https://cdn.staticfile.org/layui/2.6.8/layui.js"></script>
<script src="../src/layui.js" src1="https://cdn.staticfile.org/layui/2.7.6/layui.js"></script>
<script>
layui.use(['upload', 'element'], function(){
layui.use(['upload', 'element', 'form'], function(){
var $ = layui.$;
var upload = layui.upload;
var element = layui.element;
// 模拟接口
var url = '' // 'https://httpbin.org/post';
// 创建实例
var uploadInst = upload.render({
elem: '#test1',
url: 'https://httpbin.org/post',
url: url, // 若需模拟上传过程,而不真实上传文件,可使用开源的 HTTP 模拟接口: httpbin
// size: 2000, //限制文件大小,单位 KB
// accept: 'file',
method: 'get',
@ -149,19 +152,19 @@ layui.use(['upload', 'element'], function(){
element.progress('demo', n + '%'); //可配合 layui 进度条元素使用
}
});
// 重置上述 upload 实例
// 重载上述实例
uploadInst.reload({
name:'avatar',
field: 'avatar',
accept: 'images', // 只允许上传图片
acceptMime: 'image/*', // 只筛选图片
//,size: 2
// size: 2,
});
// 演示多图片上传
upload.render({
elem: '#test2',
url: 'https://httpbin.org/post',
url: url, // 实际使用时改成您自己的上传接口即可
multiple: true, // 多文件
unified: true, // 一起上传 --- 2.8.8+
accept: 'images',
@ -188,7 +191,7 @@ layui.use(['upload', 'element'], function(){
var demoListView = $('#demoList');
var uploadListIns = upload.render({
elem: '#testList',
url: 'https://httpbin.org/post',
url: url, // 实际使用时改成您自己的上传接口即可
accept: 'file',
multiple: true,
number: 5,
@ -252,17 +255,16 @@ layui.use(['upload', 'element'], function(){
element.progress('progress-'+ index, n + '%'); //进度条
}
});
upload.render({
elem: '.test333',
url: 'a',
url: url,
accept: 'file',
before: function(obj){
console.log(this.item);
choose: function(obj){
console.log(this.elem);
},
done: function(res){
console.log(res)
console.log(res);
}
});
@ -271,6 +273,7 @@ layui.use(['upload', 'element'], function(){
done: function(res, index, upload){
//获取当前触发上传的元素,一般用于 elem 绑定 class 的情况,注意:此乃 layui 2.1.0 新增
var item = this.item;
}
})
@ -286,7 +289,7 @@ layui.use(['upload', 'element'], function(){
upload.render({
elem: '#test4',
url: '',
url: url, // 实际使用时改成您自己的上传接口即可
accept: 'video',
done: function(res){
console.log(res)
@ -306,7 +309,7 @@ layui.use(['upload', 'element'], function(){
//手动上传
upload.render({
elem: '#test6',
url: '',
url: url, // 实际使用时改成您自己的上传接口即可
auto: false,
// multiple: true,
bindAction: '#test7',
@ -328,7 +331,7 @@ layui.use(['upload', 'element'], function(){
upload.render({
elem: '#test8',
url: 'https://httpbin.org/post',
url: url, // 实际使用时改成您自己的上传接口即可
done: function(res){
console.log(res);
}
@ -336,7 +339,7 @@ layui.use(['upload', 'element'], function(){
upload.render({
elem: '#test9',
url: '',
url: url, // 实际使用时改成您自己的上传接口即可
done: function(res){
console.log(res);
}

View File

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

View File

@ -805,6 +805,7 @@ a cite{font-style: normal; *cursor:pointer;}
.layui-input-wrap .layui-input-split{pointer-events: none;}
.layui-input-wrap .layui-input:hover + .layui-input-split{border-color: #d2d2d2;}
.layui-input-wrap .layui-input:focus + .layui-input-split{border-color: #16b777;}
.layui-input-wrap .layui-input.layui-form-danger:focus + .layui-input-split{border-color: #ff5722;}
.layui-input-wrap .layui-input-prefix.layui-input-split{border-width: 0; border-right-width: 1px;}
/* 输入框动态点缀 */
@ -1273,6 +1274,7 @@ body .layui-table-tips .layui-layer-content{background: none; padding: 0; box-sh
.layui-nav .layui-nav-more{position: absolute; top: 0; right: 3px; left: auto !important; margin-top: 0; font-size: 12px; cursor: pointer; transition: all .2s; -webkit-transition: all .2s;}
.layui-nav .layui-nav-mored,
.layui-nav-expand > a .layui-nav-more,
.layui-nav-itemed > a .layui-nav-more{transform: rotate(180deg);}
@ -1305,16 +1307,17 @@ body .layui-table-tips .layui-layer-content{background: none; padding: 0; box-sh
.layui-nav-itemed>a{color: #fff !important;}
.layui-nav-tree .layui-nav-bar{background-color: #16baaa;}
.layui-nav-tree .layui-nav-child{position: relative; z-index: 0; top: 0; border: none; box-shadow: none;}
.layui-nav-tree .layui-nav-child{position: relative; z-index: 0; top: 0; border: none; background-color: rgba(0,0,0,.3); box-shadow: none;}
.layui-nav-tree .layui-nav-child dd{margin: 0;}
.layui-nav-tree .layui-nav-child a{color: #fff; color: rgba(255,255,255,.7);}
.layui-nav-tree .layui-nav-child a:hover,
.layui-nav-tree .layui-nav-child{background: none; color: #fff;}
.layui-nav-tree .layui-nav-child a:hover{background: none; color: #fff;}
.layui-nav-itemed>.layui-nav-child{display: block; background-color: rgba(0,0,0,.3) !important;}
/* 垂直导航 - 展开状态 */
.layui-nav-itemed>.layui-nav-child,
.layui-nav-itemed>.layui-nav-child>.layui-this>.layui-nav-child{display: block;}
/* 侧边 */.layui-nav-side{position: fixed; top: 0; bottom: 0; left: 0; overflow-x: hidden; z-index: 999;}
/* 垂直导航 - 侧边 */
.layui-nav-side{position: fixed; top: 0; bottom: 0; left: 0; overflow-x: hidden; z-index: 999;}
/* 导航浅色背景 */
.layui-nav.layui-bg-gray .layui-nav-item a,
@ -1322,7 +1325,7 @@ body .layui-table-tips .layui-layer-content{background: none; padding: 0; box-sh
.layui-nav-tree.layui-bg-gray{padding: 6px 0;}
.layui-nav-tree.layui-bg-gray .layui-nav-itemed>a{color: #000 !important;}
.layui-nav.layui-bg-gray .layui-this a{color: #16b777;}
.layui-nav-tree.layui-bg-gray .layui-nav-itemed>.layui-nav-child{padding-left: 11px; background: none!important;}
.layui-nav-tree.layui-bg-gray .layui-nav-child{padding-left: 11px; background: none;}
.layui-nav-tree.layui-bg-gray .layui-nav-item>a{padding-top: 0; padding-bottom: 0;}
.layui-nav-tree.layui-bg-gray .layui-nav-item>a .layui-nav-more{padding: 0;}
.layui-nav-tree.layui-bg-gray .layui-this,

View File

@ -37,7 +37,9 @@ html #layuicss-skincodecss{display: none; position: absolute; width: 1989px;}
.layui-code-view:hover > .layui-code-fixbar .layui-code-lang-marker{display: none;}
/* 深色主题 */
.layui-code-theme-dark{border-width: 1px; border-color: rgb(126 122 122 / 15%); background-color: #1f1f1f; color: #ccc;}
.layui-code-theme-dark,
.layui-code-theme-dark > .layui-code-header{border-color: rgb(126 122 122 / 15%); background-color: #1f1f1f;}
.layui-code-theme-dark{border-width: 1px; color: #ccc;}
.layui-code-theme-dark > .layui-code-ln-side{border-right-color: #2a2a2a; background: none; color: #6e7681;}

View File

@ -16,7 +16,7 @@
};
var Layui = function(){
this.v = '2.8.17'; // Layui 版本号
this.v = '2.8.18-beta'; // Layui 版本号
};
// 识别预先可能定义的指定全局对象

View File

@ -299,12 +299,12 @@ layui.define(['jquery', 'lay'], function(exports){
}, 50);
}
// 移除过
// 移除过
setTimeout(function(){
elemItem.removeClass(THIS + ' ' + ELEM_PREV + ' ' + ELEM_NEXT + ' ' + ELEM_LEFT + ' ' + ELEM_RIGHT);
elemItem.eq(options.index).addClass(THIS);
that.haveSlide = false; // 解锁
}, 300);
}, 350);
// 指示器焦点
that.elemInd.find('li').eq(options.index).addClass(THIS)

View File

@ -25,7 +25,6 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
ELEM_LINE: 'layui-code-line',
ELEM_LINE_NUM: 'layui-code-line-number',
ELEM_LN_MODE: 'layui-code-ln-mode',
CDDE_DATA_CODE: 'LayuiCodeDataCode',
CDDE_DATA_CLASS: 'LayuiCodeDataClass',
LINE_RAW_WIDTH: 45, // 行号初始宽度,需与 css 保持一致
};
@ -113,11 +112,8 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
// 未使用 codeRender 时若开启了预览,则强制开启编码
options.encode = (options.encode || options.preview) && !options.codeRender;
// 最终显示的代码
var finalCode;
// 获得初始 code
var rawCode = othis.data(CONST.CDDE_DATA_CODE) || function(){
options.code = options.code || function(){
var arr = [];
var textarea = othis.children('textarea');
@ -131,12 +127,9 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
arr.push(trim(othis.html()));
}
return arr;
return arr.join('');
}();
// 记录初始 code
othis.data(CONST.CDDE_DATA_CODE, rawCode);
// 创建 code 行结构
var createCode = function(html) {
// codeRender
@ -171,13 +164,21 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
};
};
// 原始 code
var rawCode = options.code;
// 最终 code
var finalCode = function(code) {
return typeof options.codeParse === 'function' ?
options.codeParse(code, options) :
code;
};
// 仅重载 code
if (mode === 'reloadCode') {
(function(html) {
var rst = createCode(html);
othis.children('.layui-code-wrap').html(rst.html);
})(rawCode.join(''))
return ret;
return othis.children('.layui-code-wrap').html(
createCode(finalCode(rawCode)).html
), ret;
}
// 自增索引
@ -195,21 +196,13 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
othis.data(CONST.CDDE_DATA_CLASS, othis.attr('class'));
}
// code
var html = finalCode = rawCode.join('');
// 外部重新解析 code
if(typeof options.codeParse === 'function'){
html = finalCode = options.codeParse(html);
}
// 工具栏
var tools = {
copy: {
className: 'file-b',
title: ['复制代码'],
event: function(obj){
var code = util.unescape(finalCode);
var code = util.unescape(finalCode(options.code));
// 写入剪切板
lay.clipboard.writeText({
@ -282,19 +275,19 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
var classNameFull = 'layui-icon-'+ this.className;
var classNameRestore = 'layui-icon-screen-restore';
var title = this.title;
var html = $('html,body');
var htmlElem = $('html,body');
var ELEM_SCROLLBAR_HIDE = 'layui-scrollbar-hide';
if(el.hasClass(classNameFull)){
elemView.addClass(CONST.ELEM_FULL);
el.removeClass(classNameFull).addClass(classNameRestore);
el.attr('title', title[1]);
html.addClass(ELEM_SCROLLBAR_HIDE);
htmlElem.addClass(ELEM_SCROLLBAR_HIDE);
} else {
elemView.removeClass(CONST.ELEM_FULL);
el.removeClass(classNameRestore).addClass(classNameFull);
el.attr('title', title[0]);
html.removeClass(ELEM_SCROLLBAR_HIDE);
htmlElem.removeClass(ELEM_SCROLLBAR_HIDE);
}
}
},
@ -303,7 +296,7 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
title: ['在新窗口预览'],
event: function(obj){
util.openWin({
content: finalCode
content: finalCode(options.code)
});
}
}
@ -329,8 +322,8 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
elem: oi,
type: type,
options: options, // 当前属性选项
rawCode: rawCode.join(''), // 原始 code
finalCode: util.unescape(finalCode) // 最终 code
rawCode: options.code, // 原始 code
finalCode: util.unescape(finalCode(options.code)) // 最终 code
};
// 内部 tools event
@ -341,8 +334,8 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
});
// 增加工具栏
if (options.addTools) {
options.tools = [].concat(options.tools || [], options.addTools);
if (options.addTools && options.tools) {
options.tools = [].concat(options.tools, options.addTools);
}
// 渲染工具栏
@ -384,32 +377,33 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
}
// 执行预览
var run = function(thisItemBody){
var runPreview = function(thisItemBody){
var iframe = thisItemBody.children('iframe')[0];
// 是否 iframe 方式预览
if(isIframePreview && iframe){
iframe.srcdoc = finalCode;
iframe.srcdoc = finalCode(options.code);
} else {
thisItemBody.html(rawCode.join(''));
thisItemBody.html(options.code);
}
// 回调的返回参数
var params = {
container: thisItemBody,
render: function(){
form.render(thisItemBody.find('.layui-form'));
element.render();
}
};
// 当前实例预览完毕后的回调
setTimeout(function(){
typeof options.done === 'function' && options.done(params);
typeof options.done === 'function' && options.done({
container: thisItemBody,
options: options,
render: function(){
form.render(thisItemBody.find('.layui-form'));
element.render();
}
});
},3);
};
if(layout[0] === 'preview'){
elemPreviewView.addClass(CONST.ELEM_SHOW);
othis.before(elemPreviewView);
run(elemPreviewView);
runPreview(elemPreviewView);
} else {
othis.addClass(CONST.ELEM_SHOW).after(elemPreviewView);
}
@ -429,7 +423,7 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
thisItemBody.addClass(CONST.ELEM_SHOW);
if($this.attr('lay-id') === 'preview'){
run(thisItemBody);
runPreview(thisItemBody);
}
setCodeLayout();
@ -461,10 +455,10 @@ layui.define(['lay', 'util', 'element', 'form'], function(exports){
].join(' '));
}
// 转义 HTML 标签
if(options.encode) html = util.escape(html); // 编码
var createCodeRst = createCode(html);
// 获取 code 行结构
var createCodeRst = createCode(
options.encode ? util.escape(finalCode(rawCode)) : rawCode // 是否编码
);
var lines = createCodeRst.lines;
// 插入 code

View File

@ -272,14 +272,14 @@ layui.define('jquery', function(exports){
)
*/
//点击菜单 - a标签触发
// 点击菜单 - a 标签触发
,clickThis: function(){
var othis = $(this)
,parents = othis.parents(NAV_ELEM)
,filter = parents.attr('lay-filter')
,parent = othis.parent()
,child = othis.siblings('.'+NAV_CHILD)
,unselect = typeof parent.attr('lay-unselect') === 'string'; //是否禁用选中
var othis = $(this);
var parents = othis.parents(NAV_ELEM);
var filter = parents.attr('lay-filter');
var parent = othis.parent() ;
var child = othis.siblings('.'+NAV_CHILD);
var unselect = typeof parent.attr('lay-unselect') === 'string'; // 是否禁用选中
if(!(othis.attr('href') !== 'javascript:;' && othis.attr('target') === '_blank') && !unselect){
if(!child[0]){
@ -288,15 +288,27 @@ layui.define('jquery', function(exports){
}
}
//如果是垂直菜单
// 若为垂直菜单
if(parents.hasClass(NAV_TREE)){
var NAV_ITEMED = NAV_ITEM + 'ed';
var NAV_EXPAND = 'layui-nav-expand';
var isNone = child.css('display') === 'none';
child.removeClass(NAV_ANIM);
//如果有子菜单,则展开
//有子菜单,则展开
if(child[0]){
parent[child.css('display') === 'none' ? 'addClass': 'removeClass'](NAV_ITEM+'ed');
if(parents.attr('lay-shrink') === 'all'){
parent.siblings().removeClass(NAV_ITEM + 'ed');
child.slideToggle(200, function() {
isNone || parent.removeClass(NAV_ITEMED);
});
parent[isNone ? 'addClass': 'removeClass'](NAV_EXPAND);
// 手风琴
if(typeof parents.attr('lay-accordion') === 'string' || parents.attr('lay-shrink') === 'all'){
// 收缩兄弟项
parent.siblings().removeClass([
NAV_ITEMED,
NAV_EXPAND
].join(' ')).children('.'+NAV_CHILD).slideUp(200);
}
}
}
@ -304,26 +316,16 @@ layui.define('jquery', function(exports){
layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis);
}
//点击子菜单选中
/*
,clickChild: function(){
var othis = $(this), parents = othis.parents(NAV_ELEM)
,filter = parents.attr('lay-filter');
parents.find('.'+THIS).removeClass(THIS);
othis.addClass(THIS);
layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis);
}
*/
//折叠面板
// 折叠面板
,collapse: function(){
var othis = $(this), icon = othis.find('.layui-colla-icon')
,elemCont = othis.siblings('.layui-colla-content')
,parents = othis.parents('.layui-collapse').eq(0)
,filter = parents.attr('lay-filter')
,isNone = elemCont.css('display') === 'none';
var othis = $(this);
var icon = othis.find('.layui-colla-icon');
var elemCont = othis.siblings('.layui-colla-content');
var parents = othis.parents('.layui-collapse').eq(0);
var filter = parents.attr('lay-filter');
var isNone = elemCont.css('display') === 'none';
//是否手风琴
// 是否手风琴
if(typeof parents.attr('lay-accordion') === 'string'){
var show = parents.children('.layui-colla-item').children('.'+SHOW);
show.siblings('.layui-colla-title').children('.layui-colla-icon').html('&#xe602;');

View File

@ -174,6 +174,48 @@ layui.define(['lay', 'layer', 'util'], function(exports){
// 初始化全局的 autocomplete
options.autocomplete && inputs.attr('autocomplete', options.autocomplete);
var handleInputNumberEvents = function(elem, eventType){
var that = this;
var rawValue = elem.val();
var value = Number(rawValue);
var step = Number(elem.attr('step')) || 1; // 加减的数字间隔
var min = Number(elem.attr('min'));
var max = Number(elem.attr('max'));
var precision = Number(elem.attr('lay-precision'));
var noAction = eventType === 'blur' && rawValue === '' // 失焦时空值不作处理
if(isNaN(value)) return; // 若非数字,则不作处理
if(eventType === 'click'){
var isDecrement = !!$(that).index() // 0: icon-up, 1: icon-down
value = isDecrement ? value - step : value + step;
}
// 获取小数点后位数
var decimals = function(step){
var decimals = (step.toString().match(/\.(\d+$)/) || [])[1] || '';
return decimals.length;
};
precision = precision >= 0 ? precision : Math.max(decimals(step), decimals(rawValue));
if(!noAction){
if(value <= min) value = min;
if(value >= max) value = max;
if(precision) value = value.toFixed(precision);
elem.val(value)
}
// 更新按钮状态
var controlBtn = {
increment: elem.next().find('.layui-icon-up'),
decrement: elem.next().find('.layui-icon-down')
}
controlBtn.increment[(value >= max && !noAction) ? 'addClass' : 'removeClass'](DISABLED)
controlBtn.decrement[(value <= min && !noAction) ? 'addClass' : 'removeClass'](DISABLED)
}
// 初始化输入框动态点缀
elemForm.find('input[lay-affix],textarea[lay-affix]').each(function(){
var othis = $(this);
@ -248,6 +290,11 @@ layui.define(['lay', 'layer', 'util'], function(exports){
var value = this.value;
opts.show === 'auto' && showAffix(elemAffix, value);
});
// 失去焦点事件
othis.on('blur', function(){
typeof opts.blur === 'function' && opts.blur.call(this, othis, opts);
});
// 点击动态后缀事件
elemIcon.on('click', function(){
@ -295,35 +342,11 @@ layui.define(['lay', 'layer', 'util'], function(exports){
className: 'layui-input-number',
disabled: othis.is('[disabled]'), // 跟随输入框禁用状态
click: function(elem){
var index = $(this).index();
var value = elem.val();
var rawValue = value;
var step = Number(elem.attr('step')) || 1; // 加减的数字间隔
var min = Number(elem.attr('min'));
var max = Number(elem.attr('max'));
if(isNaN(value)) return; // 若非数字,则不作处理
value = Number(value);
value = index ? value - step : value + step;
// min max
if(value < min) value = min;
if(value > max) value = max;
// 获取小数点后位数
var decimals = function(step){
var decimals = (step.toString().match(/\.(\d+$)/) || [])[1] || '';
return decimals.length;
};
// 位数比较
var fixed = Math.max(decimals(step), decimals(rawValue));
if(fixed) value = value.toFixed(fixed);
elem.val(value);
}
handleInputNumberEvents.call(this, elem, 'click')
},
blur: function(elem){
handleInputNumberEvents.call(this, elem, 'blur')
},
}
};

View File

@ -2178,9 +2178,9 @@
return that;
};
//初始执行
// 初始执行
ready.run = function(lay){
//绑定关闭控件事件
// 绑定关闭控件事件
lay(document).on('mousedown', function(e){
if(!laydate.thisId) return;
var that = thisModule.getThis(laydate.thisId);
@ -2191,7 +2191,8 @@
if(
e.target === options.elem[0] ||
e.target === options.eventElem[0] ||
e.target === lay(options.closeStop)[0]
e.target === lay(options.closeStop)[0] ||
(options.elem[0] && options.elem[0].contains(e.target))
) return;
that.remove();

View File

@ -1719,6 +1719,23 @@ layer.photos = function(options, loop, key){
ready.run = function(_$){
$ = _$;
win = $(window);
// 移动端兼容性处理
// https://gitee.com/layui/layui/issues/I81WGC
// https://github.com/jquery/jquery/issues/1729
var agent = navigator.userAgent.toLowerCase();
var isMobile = /android|iphone|ipod|ipad|ios/.test(agent)
var _win = $(window);
if(isMobile){
$.each({Height: "height", Width: "width"}, function(propSuffix, funcName){
var propName = 'inner' + propSuffix;
win[funcName] = function(){
return propName in window
? window[propName]
: _win[funcName]()
}
})
}
doms.html = $('html');
layer.open = function(deliver){
var o = new Class(deliver);

View File

@ -19,7 +19,7 @@ layui.define(['jquery', 'lay'],function(exports){
that.config = $.extend({}, that.config, options);
return that;
},
//事件
on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
@ -64,14 +64,14 @@ layui.define(['jquery', 'lay'],function(exports){
readonly: false, //是否只读
half: false, //是否可以半星
value: 0, //星星选中个数
theme: ''
theme: '' //主题颜色
};
//评分渲染
Class.prototype.render = function(){
var that = this;
var options = that.config;
// 若 elem 非唯一,则拆分为多个实例
var elem = $(options.elem);
if(elem.length > 1){
@ -88,9 +88,9 @@ layui.define(['jquery', 'lay'],function(exports){
// 自定义主题
var style = options.theme ? ('style="color: '+ options.theme + ';"') : '';
options.elem = $(options.elem);
//最大值不能大于总长度
if(options.value > options.length){
options.value = options.length;
@ -121,12 +121,12 @@ layui.define(['jquery', 'lay'],function(exports){
//开始插入替代元素
var othis = options.elem;
var hasRender = othis.next('.' + ELEM_VIEW);
//生成替代元素
hasRender[0] && hasRender.remove(); //如果已经渲染则Rerender
that.elemTemp = $(temp);
options.span = that.elemTemp.next('span');
options.setText && options.setText(options.value);
@ -136,7 +136,7 @@ layui.define(['jquery', 'lay'],function(exports){
othis.addClass("layui-inline");
//如果不是只读,那么进行触控事件
if(!options.readonly) that.action();
if(!options.readonly) that.action();
};
@ -180,7 +180,7 @@ layui.define(['jquery', 'lay'],function(exports){
//移入
othis.on('mousemove', function(e){
_ul.find("i").each(function(){
_ul.find("i").each(function(){
$(this).addClass(ICON_RATE).removeClass(ICON_SOLID_HALF)
});
_ul.find("i:lt(" + ind + ")").each(function(){
@ -192,7 +192,7 @@ layui.define(['jquery', 'lay'],function(exports){
if(x <= wide / 2){
othis.children("i").addClass(ICON_RATE_HALF).removeClass(ICON_RATE_SOLID)
}
}
}
})
//移出
@ -206,14 +206,14 @@ layui.define(['jquery', 'lay'],function(exports){
//如果设置可选半星,根据分数判断是否有半星
if(options.half){
if(parseInt(options.value) !== options.value){
_ul.children("li:eq(" + Math.floor(options.value) + ")").children("i").addClass(ICON_RATE_HALF).removeClass(ICON_SOLID_RATE)
_ul.children("li:eq(" + Math.floor(options.value) + ")").children("i").addClass(ICON_RATE_HALF).removeClass(ICON_SOLID_RATE)
}
}
}
})
})
};
//事件处理
Class.prototype.events = function () {
var that = this;
@ -225,6 +225,6 @@ layui.define(['jquery', 'lay'],function(exports){
var inst = new Class(options);
return thisRate.call(inst);
};
exports(MOD_NAME, rate);
})

View File

@ -19,13 +19,13 @@ layui.define(['jquery', 'lay'], function(exports){
that.config = $.extend({}, that.config, options);
return that;
}
// 事件
,on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
};
// 操作当前实例
var thisSlider = function(){
var that = this
@ -97,25 +97,25 @@ layui.define(['jquery', 'lay'], function(exports){
// 合并 lay-options 属性上的配置信息
$.extend(options, lay.options(elem[0]));
//间隔值不能小于 1
if(options.step < 1) options.step = 1;
//最大值不能小于最小值
if(options.max < options.min) options.max = options.min + options.step;
//判断是否开启双滑块
if(options.range){
options.value = typeof(options.value) == 'object' ? options.value : [options.min, options.value];
var minValue = Math.min(options.value[0], options.value[1])
,maxValue = Math.max(options.value[0], options.value[1]);
options.value[0] = minValue > options.min ? minValue : options.min;
options.value[1] = maxValue > options.min ? maxValue : options.min;
options.value[0] = options.value[0] > options.max ? options.max : options.value[0];
options.value[1] = options.value[1] > options.max ? options.max : options.value[1];
options.value[0] = Math.max(minValue,options.min);
options.value[1] = Math.max(maxValue,options.min);
options.value[0] = Math.min(options.value[0],options.max);
options.value[1] = Math.min(options.value[1],options.max);
var scaleFir = Math.floor((options.value[0] - options.min) / (options.max - options.min) * 100)
,scaleSec = Math.floor((options.value[1] - options.min) / (options.max - options.min) * 100)
,scale = scaleSec - scaleFir + '%';
@ -126,44 +126,44 @@ layui.define(['jquery', 'lay'], function(exports){
if(typeof options.value == 'object'){
options.value = Math.min.apply(null, options.value);
}
//初始值不能小于最小值且不能大于最大值
if(options.value < options.min) options.value = options.min;
if(options.value > options.max) options.value = options.max;
var scale = Math.floor((options.value - options.min) / (options.max - options.min) * 100) + '%';
};
}
//如果禁用,颜色为统一的灰色
var theme = options.disabled ? '#c2c2c2' : options.theme;
//滑块
var temp = '<div class="layui-slider '+ (options.type === 'vertical' ? 'layui-slider-vertical' : '') +'">'+ (options.tips ? '<div class="'+ SLIDER_TIPS +'"></div>' : '') +
var temp = '<div class="layui-slider '+ (options.type === 'vertical' ? 'layui-slider-vertical' : '') +'">'+ (options.tips ? '<div class="'+ SLIDER_TIPS +'"></div>' : '') +
'<div class="layui-slider-bar" style="background:'+ theme +'; '+ (options.type === 'vertical' ? 'height' : 'width') +':'+ scale +';'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ (scaleFir || 0) +';"></div><div class="layui-slider-wrap" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ (scaleFir || scale) +';">' +
'<div class="layui-slider-wrap-btn" style="border: 2px solid '+ theme +';"></div></div>'+ (options.range ? '<div class="layui-slider-wrap" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ scaleSec +';"><div class="layui-slider-wrap-btn" style="border: 2px solid '+ theme +';"></div></div>' : '') +'</div>';
var othis = $(options.elem)
,hasRender = othis.next('.' + ELEM_VIEW);
//生成替代元素
hasRender[0] && hasRender.remove(); //如果已经渲染则Rerender
hasRender[0] && hasRender.remove(); //如果已经渲染则Rerender
that.elemTemp = $(temp);
//把数据缓存到滑块上
if(options.range){
that.elemTemp.find('.' + SLIDER_WRAP).eq(0).data('value', options.value[0]);
that.elemTemp.find('.' + SLIDER_WRAP).eq(1).data('value', options.value[1]);
that.elemTemp.find('.' + SLIDER_WRAP).eq(1).data('value', options.value[1]);
}else{
that.elemTemp.find('.' + SLIDER_WRAP).data('value', options.value);
};
}
//插入替代元素
othis.html(that.elemTemp);
othis.html(that.elemTemp);
//垂直滑块
if(options.type === 'vertical'){
that.elemTemp.height(options.height + 'px');
};
}
//显示间断点
if(options.showstep){
@ -173,9 +173,9 @@ layui.define(['jquery', 'lay'], function(exports){
if(step < 100){
item += '<div class="layui-slider-step" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ step +'%"></div>'
}
};
}
that.elemTemp.append(item);
};
}
//插入输入框
if(options.input && !options.range){
@ -191,7 +191,7 @@ layui.define(['jquery', 'lay'], function(exports){
} else {
that.elemTemp.css("margin-right", elemInput.outerWidth() + 15);
}
};
}
//给未禁止的滑块滑动事件
if(!options.disabled){
@ -199,7 +199,7 @@ layui.define(['jquery', 'lay'], function(exports){
}else{
that.elemTemp.addClass(DISABLED);
that.elemTemp.find('.' + SLIDER_WRAP_BTN).addClass(DISABLED);
};
}
//划过滑块显示数值
var timer;
@ -216,21 +216,21 @@ layui.define(['jquery', 'lay'], function(exports){
timer = setTimeout(function(){
if(options.type === 'vertical'){
that.elemTemp.find('.' + SLIDER_TIPS).css({
"bottom": left + '%',
"margin-bottom": "20px",
"bottom": left + '%',
"margin-bottom": "20px",
"display": "inline-block"
});
} else {
that.elemTemp.find('.' + SLIDER_TIPS).css({
"left": left + '%',
"left": left + '%',
"display": "inline-block"
});
};
}
}, 300);
}).on('mouseout', function(){
clearTimeout(timer);
that.elemTemp.find('.' + SLIDER_TIPS).css("display", "none");
});
});
};
//滑块滑动
@ -250,7 +250,7 @@ layui.define(['jquery', 'lay'], function(exports){
offsetValue = Math.ceil(offsetValue) * step
}else{
offsetValue = Math.round(offsetValue) * step
};
}
offsetValue = offsetValue > 100 ? 100: offsetValue;
offsetValue = offsetValue < 0 ? 0: offsetValue;
sliderWrap.eq(index).css((options.type === 'vertical' ?'bottom':'left'), offsetValue + '%');
@ -262,7 +262,7 @@ layui.define(['jquery', 'lay'], function(exports){
secLeft = options.range ? valueTo(sliderWidth() - sliderWrap[1].offsetTop - sliderWrap.height()) : 0;
}else{
sliderAct.find('.' + SLIDER_TIPS).css("left",offsetValue + '%');
};
}
firLeft = firLeft > 100 ? 100: firLeft;
secLeft = secLeft > 100 ? 100: secLeft;
var minLeft = Math.min(firLeft, secLeft)
@ -271,13 +271,13 @@ layui.define(['jquery', 'lay'], function(exports){
sliderAct.find('.' + SLIDER_BAR).css({"height":wrapWidth + '%', "bottom":minLeft + '%'});
}else{
sliderAct.find('.' + SLIDER_BAR).css({"width":wrapWidth + '%', "left":minLeft + '%'});
};
}
var selfValue = options.min + Math.round((options.max - options.min) * offsetValue / 100);
inputValue = selfValue;
sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val(inputValue);
sliderWrap.eq(index).data('value', selfValue);
sliderAct.find('.' + SLIDER_TIPS).html(options.setTips ? options.setTips(selfValue) : selfValue);
//如果开启范围选择,则返回数组值
if(options.range){
var arrValue = [
@ -298,10 +298,10 @@ layui.define(['jquery', 'lay'], function(exports){
,left = Math.round(oldLeft) * step;
if(value == sliderWidth()){
left = Math.ceil(oldLeft) * step;
};
}
return left;
}
//拖拽元素
,elemMove = $(['<div class="layui-auxiliar-moving" id="LAY-slider-moving"></div'].join(''))
,createMoveElem = function(move, up){
@ -314,7 +314,7 @@ layui.define(['jquery', 'lay'], function(exports){
elemMove.on('mousemove', move);
elemMove.on('mouseup', upCall).on('mouseleave', upCall);
};
//动态赋值
if(setValue === 'set') return change(value - options.min, i, 'done');
@ -323,14 +323,14 @@ layui.define(['jquery', 'lay'], function(exports){
var othis = $(this);
othis.on('mousedown', function(e){
e = e || window.event;
var oldleft = othis.parent()[0].offsetLeft
,oldx = e.clientX;
if(options.type === 'vertical'){
oldleft = sliderWidth() - othis.parent()[0].offsetTop - sliderWrap.height()
oldx = e.clientY;
};
}
var move = function(e){
e = e || window.event;
var left = oldleft + (options.type === 'vertical' ? (oldx - e.clientY) : (e.clientX - oldx));
@ -342,23 +342,23 @@ layui.define(['jquery', 'lay'], function(exports){
sliderAct.find('.' + SLIDER_TIPS).show();
e.preventDefault();
};
var up = function(){
othis.removeClass(ELEM_HOVER);
sliderAct.find('.' + SLIDER_TIPS).hide();
};
createMoveElem(move, up)
});
});
// 点击滑块
sliderAct.on('click', function(e){
var main = $('.' + SLIDER_WRAP_BTN);
var othis = $(this);
if(!main.is(event.target) && main.has(event.target).length === 0 && main.length){
var index;
var offset = options.type === 'vertical'
var offset = options.type === 'vertical'
? (sliderWidth() - e.clientY + othis.offset().top - $(window).scrollTop())
:(e.clientX - othis.offset().left - $(window).scrollLeft());
@ -373,30 +373,30 @@ layui.define(['jquery', 'lay'], function(exports){
}
} else {
index = 0;
};
}
change(reaLeft, index, 'done');
e.preventDefault();
}
});
//点击加减输入框
sliderTxt.children('.' + SLIDER_INPUT_BTN).children('i').each(function(index){
$(this).on('click', function(){
inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val();
if(index == 1){ //减
inputValue = inputValue - options.step < options.min
? options.min
inputValue = inputValue - options.step < options.min
? options.min
: Number(inputValue) - options.step;
}else{
inputValue = Number(inputValue) + options.step > options.max
? options.max
inputValue = Number(inputValue) + options.step > options.max
? options.max
: Number(inputValue) + options.step;
};
}
var inputScale = (inputValue - options.min) / (options.max - options.min) * 100 / step;
change(inputScale, 0, 'done');
});
});
//获取输入框值
var getInputValue = function(){
var realValue = this.value;
@ -412,7 +412,7 @@ layui.define(['jquery', 'lay'], function(exports){
e.preventDefault();
getInputValue.call(this);
}
}).on('change', getInputValue);
}).on('change', getInputValue);
};
//事件处理
@ -423,9 +423,9 @@ layui.define(['jquery', 'lay'], function(exports){
//核心入口
slider.render = function(options){
var inst = new Class(options);
var inst = new Class(options);
return thisSlider.call(inst);
};
exports(MOD_NAME, slider);
})
})

View File

@ -572,8 +572,13 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
'{'+ lineStyle +'}',
'.layui-table-cell{height: auto; max-height: '+ cellMaxHeight +'; white-space: normal; text-overflow: clip;}',
'> td:hover > .layui-table-cell{overflow: auto;}'
], function(i, val) {
text.push(trClassName + ' ' + val);
].concat(
device.ie ? [
'.layui-table-edit{height: '+ cellMaxHeight +';}',
'td[data-edit]:hover:after{height: '+ cellMaxHeight +';}'
] : []
), function(i, val) {
val && text.push(trClassName + ' ' + val);
});
})(options.lineStyle);
@ -1027,6 +1032,9 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
dataType: options.dataType || 'json',
jsonpCallback: options.jsonpCallback,
headers: options.headers || {},
complete: function(xhr,ts){
typeof options.complete === 'function' && options.complete(xhr, ts);
},
success: function(res){
// 若有数据解析的回调,则获得其返回的数据
if(typeof options.parseData === 'function'){

View File

@ -56,7 +56,7 @@ layui.define(['laytpl', 'form'], function(exports){
var getThisModuleConfig = function(id){
var config = thisModule.config[id];
if(!config) hint.error('The ID option was not found in the '+ MOD_NAME +' instance');
return; config || null;
return config || null;
};
// 字符常量

View File

@ -1791,14 +1791,30 @@ layui.define(['table'], function (exports) {
// 目前只能处理当前页的数据
return;
}
var collectNeedExpandNodeIndex = function(index){
needExpandIndex.push(index);
var trElem = tableView.find('tr[lay-data-index="' + index + '"]');
if (!trElem.length) {
var nodeData = that.getNodeDataByIndex(index);
var parentIndex = nodeData[LAY_PARENT_INDEX];
parentIndex && collectNeedExpandNodeIndex(parentIndex);
}
}
// 判断是否展开过
var trElem = tableView.find('tr[lay-data-index="' + dataIndex + '"]');
if (!trElem.length) {
var parentIndex = nodeData[LAY_PARENT_INDEX];
var needExpandIndex = [];
collectNeedExpandNodeIndex(parentIndex);
// 如果还没有展开没有渲染的要先渲染出来
treeTable.expandNode(id, {
index: nodeData[LAY_PARENT_INDEX],
expandFlag: true
});
layui.each(needExpandIndex.reverse(),function(index, nodeIndex){
treeTable.expandNode(id, {
index: nodeIndex,
expandFlag: true
});
})
trElem = tableView.find('tr[lay-data-index="' + dataIndex + '"]');
}
checkNode.call(that, trElem, checked, callbackFlag);

View File

@ -3,16 +3,22 @@
* 上传组件
*/
layui.define(['lay','layer'], function(exports){
layui.define(['lay', 'layer'], function(exports){
"use strict";
var $ = layui.$;
var lay = layui.lay;
var layer = layui.layer;
var device = layui.device();
// 模块名
var MOD_NAME = 'upload';
var MOD_INDEX = 'layui_'+ MOD_NAME +'_index'; // 模块索引名
// 外部接口
var upload = {
config: {}, // 全局配置项
index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0, // 索引
// 设置全局项
set: function(options){
var that = this;
@ -26,8 +32,13 @@ layui.define(['lay','layer'], function(exports){
};
// 操作当前实例
var thisUpload = function(){
var thisModule = function(){
var that = this;
var options = that.config;
var id = options.id;
thisModule.that[id] = that; // 记录当前实例对象
return {
upload: function(files){
that.upload.call(that, files);
@ -40,7 +51,6 @@ layui.define(['lay','layer'], function(exports){
};
// 字符常量
var MOD_NAME = 'upload';
var ELEM = 'layui-upload';
var THIS = 'layui-this';
var SHOW = 'layui-show';
@ -57,6 +67,7 @@ layui.define(['lay','layer'], function(exports){
// 构造器
var Class = function(options){
var that = this;
that.index = ++upload.index;
that.config = $.extend({}, that.config, upload.config, options);
that.render();
};
@ -86,15 +97,51 @@ layui.define(['lay','layer'], function(exports){
"limit-size": null // 限制 size 属性的提示 --- function
}
};
// 重载实例
Class.prototype.reload = function(options){
var that = this;
that.config = $.extend({}, that.config, options);
that.render(true);
};
// 初始渲染
Class.prototype.render = function(){
Class.prototype.render = function(rerender){
var that = this;
var options = that.config;
// 若 elem 非唯一
var elem = $(options.elem);
if (elem.length > 1) {
layui.each(elem, function() {
upload.render($.extend({}, options, {
elem: this
}));
});
return that;
}
// 合并 lay-options 属性上的配置信息
$.extend(options, lay.options(elem[0], {
attr: elem.attr('lay-data') ? 'lay-data' : null // 兼容旧版的 lay-data 属性
}));
// 若重复执行 render则视为 reload 处理
if (!rerender && elem[0] && elem.data(MOD_INDEX)) {
var newThat = thisModule.getThis(elem.data(MOD_INDEX));
if(!newThat) return;
return newThat.reload(options);
}
options.elem = $(options.elem);
options.bindAction = $(options.bindAction);
// 初始化 id 属性 - 优先取 options > 元素 id > 自增索引
options.id = 'id' in options ? options.id : (
elem.attr('id') || that.index
);
that.file();
that.events();
};
@ -219,11 +266,14 @@ layui.define(['lay','layer'], function(exports){
var request = function(sets){
var formData = new FormData();
// 删除正在上传中的文件队列
var removeUploaded = function(index, file) {
if (file[UPLOADING]) {
delete items[index];
return true;
// 恢复文件状态
var resetFileState = function(file) {
if (sets.unified) {
layui.each(items, function(index, file){
delete file[UPLOADING];
});
} else {
delete file[UPLOADING];
}
};
@ -234,35 +284,36 @@ layui.define(['lay','layer'], function(exports){
});
/*
*添加 file 到表单域
* 添加 file 到表单域
*/
// 是否统一上传
if (sets.unified) {
layui.each(items, function(index, file){
if (removeUploaded(index, file)) return;
file[UPLOADING] = true;
if (file[UPLOADING]) return;
file[UPLOADING] = true; // 上传中的标记
formData.append(options.field, file);
});
} else { // 逐一上传
if (removeUploaded(sets.index, sets.file)) return;
if (sets.file[UPLOADING]) return;
formData.append(options.field, sets.file);
sets.file[UPLOADING] = true; // 上传中的标记
}
sets.file[UPLOADING] = true; // 上传中的标记
// ajax 参数
var opts = {
url: options.url,
type: 'post', // 统一采用 post 上传
data: formData,
dataType: options.dataType || 'json',
contentType: false,
processData: false,
headers: options.headers || {},
success: function(res){ // 成功回调
options.unified ? (successful += that.fileLength) : successful++;
done(sets.index, res);
allDone();
allDone(sets.index);
resetFileState(sets.file);
},
error: function(e){ // 异常回调
options.unified ? (failed += that.fileLength) : failed++;
@ -271,15 +322,11 @@ layui.define(['lay','layer'], function(exports){
'status: '+ (e.status || '') +' - '+ (e.statusText || 'error')
].join('<br>'));
error(sets.index);
allDone();
allDone(sets.index);
resetFileState(sets.file);
}
};
// dataType
if (options.dataType) {
opts.dataType = options.dataType;
} else if (options.force === 'json') {
opts.dataType = options.force;
}
// 进度条
if(typeof options.progress === 'function'){
opts.xhr = function(){
@ -360,7 +407,7 @@ layui.define(['lay','layer'], function(exports){
};
// 统一网络异常回调
var error = function(index){
var error = function(index){
if(options.auto){
elemFile.value = '';
}
@ -408,7 +455,7 @@ layui.define(['lay','layer'], function(exports){
};
// 提交上传
var send = function(){
var send = function(){
// 上传前的回调 - 如果回调函数明确返回 false则停止上传
if(options.before && (options.before(args) === false)) return;
@ -433,7 +480,8 @@ layui.define(['lay','layer'], function(exports){
? ((elemFile.value.match(/[^\/\\]+\..+/g)||[]) || '')
: value;
if(value.length === 0) return;
// 若文件域值为空
if (value.length === 0) return;
// 根据文件类型校验
switch(options.accept){
@ -520,24 +568,6 @@ layui.define(['lay','layer'], function(exports){
send();
};
// 重置方法
Class.prototype.reload = function(opts){
opts = opts || {};
delete opts.elem;
delete opts.bindAction;
var that = this;
var options = that.config = $.extend({}, that.config, upload.config, opts);
var next = options.elem.next();
// 更新文件域相关属性
next.attr({
name: options.name,
accept: options.acceptMime,
multiple: options.multiple
});
};
//事件处理
Class.prototype.events = function(){
var that = this;
@ -568,23 +598,10 @@ layui.define(['lay','layer'], function(exports){
elemFile.after('<span class="layui-inline '+ ELEM_CHOOSE +'">'+ value +'</span>');
};
// 合并 lay-options/lay-data 属性配置项
var extendAttrs = function(){
var othis = $(this);
var data = othis.attr('lay-data') || othis.attr('lay-options'); // 优先兼容旧版本
if(data){
that.config = $.extend({}, options, lay.options(this, {
attr: othis.attr('lay-data') ? 'lay-data' : null
}));
}
};
// 点击上传容器
options.elem.off('upload.start').on('upload.start', function(){
var othis = $(this);
extendAttrs.call(this);
that.config.item = othis;
that.elemFile[0].click();
});
@ -604,7 +621,6 @@ layui.define(['lay','layer'], function(exports){
var files = param.originalEvent.dataTransfer.files || [];
othis.removeAttr('lay-over');
extendAttrs.call(this);
setChooseFile(files);
options.auto ? that.upload() : setChooseText(files); // 是否自动触发上传
@ -612,12 +628,11 @@ layui.define(['lay','layer'], function(exports){
}
// 文件选择
that.elemFile.off('upload.change').on('upload.change', function(){
that.elemFile.on('change', function(){
var files = this.files || [];
if(files.length === 0) return;
extendAttrs.call(this);
setChooseFile(files);
options.auto ? that.upload() : setChooseText(files); // 是否自动触发上传
@ -627,19 +642,19 @@ layui.define(['lay','layer'], function(exports){
options.bindAction.off('upload.action').on('upload.action', function(){
that.upload();
});
// 防止事件重复绑定
if(options.elem.data('haveEvents')) return;
that.elemFile.on('change', function(){
$(this).trigger('upload.change');
});
if(options.elem.data(MOD_INDEX)) return;
// 目标元素 click 事件
options.elem.on('click', function(){
if(that.isFile()) return;
$(this).trigger('upload.start');
});
// 目标元素 drop 事件
if(options.drag){
options.elem.on('dragover', function(e){
e.preventDefault();
@ -652,17 +667,29 @@ layui.define(['lay','layer'], function(exports){
});
}
// 手动上传时触发上传的元素 click 事件
options.bindAction.on('click', function(){
$(this).trigger('upload.action');
});
options.elem.data('haveEvents', true);
// 绑定元素索引
options.elem.data(MOD_INDEX, options.id);
};
// 记录所有实例
thisModule.that = {}; // 记录所有实例对象
// 获取当前实例对象
thisModule.getThis = function(id){
var that = thisModule.that[id];
if(!that) hint.error(id ? (MOD_NAME +' instance with ID \''+ id +'\' not found') : 'ID argument required');
return that;
};
// 核心入口
upload.render = function(options){
var inst = new Class(options);
return thisUpload.call(inst);
return thisModule.call(inst);
};
exports(MOD_NAME, upload);

View File

@ -1,13 +1,13 @@
/**
* util 工具组件
* util 工具组件
*/
layui.define('jquery', function(exports){
"use strict";
var $ = layui.$;
var hint = layui.hint();
// 外部接口
var util = {
// 固定块
@ -28,8 +28,8 @@ layui.define('jquery', function(exports){
var $target = $(options.target);
// 滚动条所在元素对象
var $scroll = options.scroll
? $(options.scroll)
var $scroll = options.scroll
? $(options.scroll)
: $(options.target === 'body' ? $doc : $target)
// 是否提供默认图标
@ -72,8 +72,8 @@ layui.define('jquery', function(exports){
var type = $(this).attr('lay-type');
if(type === 'top'){
(
options.target === 'body'
? $('html,body')
options.target === 'body'
? $('html,body')
: $scroll
).animate({
scrollTop : 0
@ -130,9 +130,9 @@ layui.define('jquery', function(exports){
timer = setTimeout(function(){
setTopBar();
}, 100);
});
});
},
// 倒计时
countdown: function(options){
var that = this;
@ -198,27 +198,27 @@ layui.define('jquery', function(exports){
if(countTime <= 0){
clearTimeout(inst.timer);
typeof options.done === 'function' && options.done(result, inst);
};
}
return fn;
})();
return inst;
},
// 某个时间在当前时间的多久前
timeAgo: function(time, onlyDate){
var that = this;
var arr = [[], []];
var stamp = new Date().getTime() - new Date(time).getTime();
// 返回具体日期
if(stamp > 1000*60*60*24*31){
stamp = new Date(time);
arr[0][0] = that.digit(stamp.getFullYear(), 4);
arr[0][1] = that.digit(stamp.getMonth() + 1);
arr[0][2] = that.digit(stamp.getDate());
// 是否输出时间
if(!onlyDate){
arr[1][0] = that.digit(stamp.getHours());
@ -227,7 +227,7 @@ layui.define('jquery', function(exports){
}
return arr[0].join('-') + ' ' + arr[1].join(':');
}
// 30 天以内,返回「多久前」
if(stamp >= 1000*60*60*24){
return ((stamp/1000/60/60/24)|0) + ' 天前';
@ -241,7 +241,7 @@ layui.define('jquery', function(exports){
return '刚刚';
}
},
// 数字前置补零
digit: function(num, length){
var str = '';
@ -252,13 +252,13 @@ layui.define('jquery', function(exports){
}
return num < Math.pow(10, length) ? str + (num|0) : num;
},
// 转化为日期格式字符
toDateString: function(time, format, options){
// 若 null 或空字符,则返回空字符
if(time === null || time === '') return '';
// 引用自 dayjs
// 引用自 dayjs
// https://github.com/iamkun/dayjs/blob/v1.11.9/src/constant.js#L30
var REGEX_FORMAT = /\[([^\]]+)]|y{1,4}|M{1,2}|d{1,2}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|SSS/g;
var that = this;
@ -267,7 +267,7 @@ layui.define('jquery', function(exports){
return isNaN(time) ? time : (typeof time === 'string' ? parseInt(time) : time)
}() || new Date())
if(!date.getDate()) return hint.error('Invalid Msec for "util.toDateString(Msec)"'), '';
if(!date.getDate()) return hint.error('Invalid millisecond for "util.toDateString(millisecond)"'), '';
var years = date.getFullYear();
var month = date.getMonth();
@ -313,14 +313,14 @@ layui.define('jquery', function(exports){
ss: function(){return that.digit(seconds);},
SSS: function(){return that.digit(milliseconds, 3);}
}
format = format || 'yyyy-MM-dd HH:mm:ss';
return format.replace(REGEX_FORMAT, function(match, $1) {
return $1 || (matches[match] && matches[match]()) || match;
});
},
// 转义 html
escape: function(html){
var exp = /[<"'>]|&(?=#[a-zA-Z0-9]+)/g;
@ -333,7 +333,7 @@ layui.define('jquery', function(exports){
.replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/'/g, '&#39;').replace(/"/g, '&quot;');
},
// 还原转义的 html
unescape: function(html){
if(html === undefined || html === null) html = '';
@ -354,7 +354,7 @@ layui.define('jquery', function(exports){
win.document.write(options.content || '');
win.document.close();
},
// 让指定的元素保持在可视区域
toVisibleArea: function(options){
options = $.extend({
@ -362,9 +362,9 @@ layui.define('jquery', function(exports){
duration: 200, // 动画持续毫秒数
type: 'y' // 触发方向x 水平、y 垂直
}, options);
if(!options.scrollElem[0] || !options.thisElem[0]) return;
var scrollElem = options.scrollElem // 滚动元素
var thisElem = options.thisElem // 目标元素
var vertical = options.type === 'y' // 是否垂直方向
@ -372,29 +372,29 @@ layui.define('jquery', function(exports){
var OFFSET_NAME = vertical ? 'top' : 'left' // 坐标方式
var scrollValue = scrollElem[SCROLL_NAME]() // 当前滚动距离
var size = scrollElem[vertical ? 'height' : 'width']() // 滚动元素的尺寸
var scrollOffet = scrollElem.offset()[OFFSET_NAME] // 滚动元素所处位置
var thisOffset = thisElem.offset()[OFFSET_NAME] - scrollOffet // 目标元素当前的所在位置
var scrollOffset = scrollElem.offset()[OFFSET_NAME] // 滚动元素所处位置
var thisOffset = thisElem.offset()[OFFSET_NAME] - scrollOffset // 目标元素当前的所在位置
var obj = {};
// 边界满足条件
if(thisOffset > size - options.margin || thisOffset < options.margin){
obj[SCROLL_NAME] = thisOffset - size/2 + scrollValue
scrollElem.animate(obj, options.duration);
}
},
// 批量事件
event: function(attr, obj, eventType){
var _body = $('body');
eventType = eventType || 'click';
// 记录事件回调集合
obj = util.event[attr] = $.extend(true, util.event[attr], obj) || {};
// 清除委托事件
util.event.UTIL_EVENT_CALLBACK = util.event.UTIL_EVENT_CALLBACK || {};
_body.off(eventType, '*['+ attr +']', util.event.UTIL_EVENT_CALLBACK[attr])
// 绑定委托事件
util.event.UTIL_EVENT_CALLBACK[attr] = function(){
var othis = $(this);
@ -404,13 +404,13 @@ layui.define('jquery', function(exports){
// 清除旧事件,绑定新事件
_body.on(eventType, '*['+ attr +']', util.event.UTIL_EVENT_CALLBACK[attr]);
return obj;
}
};
util.on = util.event;
// 输出接口
exports('util', util);
});
});