Browse Source

release: v2.9.2-rc.1

pull/1464/head^2
贤心 11 months ago committed by GitHub
parent
commit
246722e71c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .github/ISSUE_TEMPLATE/config.yml
  2. 30
      .github/workflows/issue-close-require.yml
  3. 82
      .github/workflows/issue-labeled.yml
  4. 18
      .github/workflows/release-npm.yml
  5. 82
      .github/workflows/release.yml
  6. 1
      CONTRIBUTING.md
  7. 20
      SECURITY.md
  8. 2
      dist/css/layui.css
  9. 2
      dist/css/layui.css.map
  10. 2
      dist/layui.js
  11. 2
      dist/layui.js.map
  12. 9
      docs/dropdown/detail/options.md
  13. 20
      docs/versions.md
  14. 102
      examples/introduce/test.html
  15. 11
      examples/introduce/免责声明.html
  16. 11
      examples/introduce/官方文档.html
  17. 3
      gulpfile.js
  18. 2
      package.json
  19. 3
      src/css/layui.css
  20. 2
      src/layui.js
  21. 18
      src/modules/carousel.js
  22. 26
      src/modules/colorpicker.js
  23. 31
      src/modules/dropdown.js
  24. 7
      src/modules/form.js
  25. 109
      src/modules/lay.js
  26. 9
      src/modules/laydate.js
  27. 24
      src/modules/layer.js
  28. 52
      src/modules/rate.js
  29. 147
      src/modules/slider.js
  30. 4
      src/modules/table.js

3
.github/ISSUE_TEMPLATE/config.yml

@ -3,3 +3,6 @@ contact_links:
- name: 📄 官方文档
url: https://layui.dev/
about: 建议在创建 Issue 之前,仔细查阅 Layui 开发文档,以便对其有更深入的了解,和更好地分析问题。
- name: 🔎 Gitee Issues
url: https://gitee.com/layui/layui/issues
about: 从过往的 6000+ Issues 中搜索相似议题,主要适用于 2.x 版本

30
.github/workflows/issue-close-require.yml

@ -0,0 +1,30 @@
name: Issue Close Require
on:
schedule:
- cron: "0 0 * * *"
permissions:
contents: read
jobs:
issue-close-require:
permissions:
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: need reproduce
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: 'need reproduce'
inactive-day: 5
body: |
由于超过 5 天仍未收到相关重现,该 issue 已被自动关闭。
- name: resolved
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: 'resolved'
inactive-day: 3

82
.github/workflows/issue-labeled.yml

@ -0,0 +1,82 @@
name: Issue Labeled
on:
issues:
types: [labeled]
permissions:
contents: read
jobs:
issue-labeled:
permissions:
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: bug
if: github.event.label.name == 'bug'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
@${{ github.event.issue.user.login }} 你好。团队已初步确认该 Bug,我们将在后续版本进行详细的排查和修复,感谢您的积极反馈 👍
- name: help wanted
if: github.event.label.name == 'help wanted'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
body: |
@${{ github.event.issue.user.login }} 很棒 👋
我们有意愿采纳这项议题,欢迎您创建 [Pull Request](https://github.com/layui/layui/pulls) 来协助实现,若变更内容涉及到 API 新增和改动,除了提交核心代码外,还需包含:[文档](https://github.com/layui/layui/tree/main/docs)、测试用例等相关文件,以便我们更好地进行 Review。期待您的贡献!
- name: invalid
if: github.event.label.name == 'invalid'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
body: |
@${{ github.event.issue.user.login }} 你好,为了提升沟通效率,我们对 Issue 制定了规范要求,你的 Issue 因不符合规范而被自动关闭。
建议您在下次创建 Issue 时,遵循表单模板规范填写。谢谢。
> 相关延伸:👉 [**提问的智慧**](https://github.com/tvvocold/How-To-Ask-Questions-The-Smart-Way)
- name: need reproduce
if: github.event.label.name == 'need reproduce'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
body: |
@${{ github.event.issue.user.login }} 您好,请提供一个最小化的重现,以便我们为您协助排查问题。良好的重现应当包括但不仅限于:
- 产生问题的详细步骤
- 与问题相关的完整代码
- 在线 Demo (推荐通过 [stackblitz](https://stackblitz.com/) 或 [codepen](https://codepen.io/) 创建)
> 相关延伸:👉 [为什么要提供最小化重现?](https://antfu.me/posts/why-reproductions-are-required-zh)
- name: discussion
if: github.event.label.name == 'discussion'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
body: |
@${{ github.event.issue.user.login }} 你好,Issue 一般只接受「Bug 报告」和「新功能请求」,而您的议题涉及到基础用法和功能疑惑等业务相关的讨论,这并不适合作为 Issue 讨论。建议您通过以下方式寻求解决方案:
- 仔细查阅 Layui 官方文档:https://layui.dev
- 搜索相关技术资料或咨询人工智能大模型
- [Discussions](https://github.com/layui/layui/discussions)
- name: unrelated
if: github.event.label.name == 'unrelated'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
body: |
@${{ github.event.issue.user.login }} 经过确认,您提出的问题与 Layui 不存在相关联。建议通过以下方式寻求解决方案:
- 搜索相关技术资料或咨询人工智能大模型
- [Discussions](https://github.com/layui/layui/discussions)

18
.github/workflows/release-npm.yml

@ -0,0 +1,18 @@
name: Publish to NPM
on:
release:
types: [created]
jobs:
publish-npm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://registry.npmjs.org
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

82
.github/workflows/release.yml

@ -0,0 +1,82 @@
on:
push:
tags:
- 'v*'
name: Create Release
jobs:
build:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Get the version
id: get_version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
# 获取当前版本贡献者
- name: Fetch Contributors
id: contributors
run: |
USERNAME_LIST=""
# 获取完整的提交历史
git fetch --prune --unshallow
# 按日期排序标签,获取上一个标签
PREVIOUS_TAG=$(git for-each-ref --sort=-creatordate --format '%(refname:short)' refs/tags | sed -n 2p)
# 获取当前标签
CURRENT_TAG=${GITHUB_REF#refs/tags/}
echo "Previous Tag: $PREVIOUS_TAG"
echo "Current Tag: $CURRENT_TAG"
for COMMIT_SHA in $(git log ${PREVIOUS_TAG}...$CURRENT_TAG --pretty=format:"%H")
do
USER=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${GITHUB_REPOSITORY}/commits/$COMMIT_SHA \
| jq -r '.author.login')
if [ "$USER" != "null" ] && [ ! -z "$USER" ]; then
USERNAME_LIST="$USERNAME_LIST @$USER"
fi
done
USERNAME_LIST=$(echo $USERNAME_LIST | tr ' ' '\n' | sort -u | tr '\n' ' ')
echo "usernames=$USERNAME_LIST" >> $GITHUB_OUTPUT
- name: Determine Prerelease
id: prerelease
run: |
if [[ ${{ github.ref }} =~ - ]]; then
echo "Setting prerelease to true"
echo "prerelease=true" >> $GITHUB_OUTPUT
else
echo "Setting prerelease to false"
echo "prerelease=false" >> $GITHUB_OUTPUT
fi
- name: Create Zip File
id: asset
run: |
DIR_NAME="layui-${{ env.VERSION }}"
mkdir -p $DIR_NAME/layui
mv dist layui
mv layui $DIR_NAME/
mv examples/introduce/* $DIR_NAME/
zip -r $DIR_NAME.zip $DIR_NAME
echo "filename=$DIR_NAME" >> $GITHUB_OUTPUT
- name: GH Release
id: create_release
uses: softprops/action-gh-release@v0.1.15
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
body: |
- **更新日志**: https://layui.dev/docs/2/versions.html#${{ env.VERSION }}
- **本次贡献**: ${{ steps.contributors.outputs.usernames }} 🎉
prerelease: ${{ steps.prerelease.outputs.prerelease }}
files: ${{ steps.asset.outputs.filename }}.zip

1
CONTRIBUTING.md

@ -13,6 +13,7 @@
其中,标题应尽量言简意赅(一句话概括议题),其他表单项则尽量将您所遇到的问题描述详细。
> **若 Issue 未遵循模板规范仔细填写,可能将无法获得相关回答,敬请知晓和理解**
> 更多细节可参考:1. [**提问的智慧**](https://github.com/tvvocold/How-To-Ask-Questions-The-Smart-Way)、2. [**请提供最小重现**](https://antfu.me/posts/why-reproductions-are-required-zh)
## 对接

20
SECURITY.md

@ -0,0 +1,20 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 2.9.x | :white_check_mark: |
| 2.8.x | :white_check_mark: |
| < 2.8.0 | :x: |
## Reporting a Vulnerability
Use this section to tell people how to report a vulnerability.
Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc.

2
dist/css/layui.css vendored

File diff suppressed because one or more lines are too long

2
dist/css/layui.css.map 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

2
dist/layui.js.map vendored

File diff suppressed because one or more lines are too long

9
docs/dropdown/detail/options.md

@ -140,13 +140,16 @@
<td>delay</td>
<td>
延迟关闭的毫秒数。当 `trigger: 'hover'` 时才生效
延迟触发的毫秒数。当 `trigger: 'hover'` 时才生效。示例:
- `delay: 300` : 表示显示与隐藏的延迟时间均为 300 毫秒
- `delay: [200, 300]` <sup>2.9.2+</sup> : 数组成员值分别表示显示延迟时间和隐藏延迟时间
</td>
<td>number</td>
<td>number/array</td>
<td>
`300`
`[200, 300]`
</td>
</tr>

20
docs/versions.md

@ -9,9 +9,27 @@ toc: true
<h2 id="2.9.x" lay-toc="{title: '2.9.x'}"></h2>
<h2 id="v2.9.2-rc.1" class="ws-anchor">
v2.9.2-rc.1
<!-- <span class="layui-badge-rim" style="color: #16b777;">稳定版</span> -->
<span class="layui-badge-rim">2023-12-16</span>
</h2>
- #### 移动端的改进
- 新增 slider, layer, carousel, laydate, rate, colorpicker 手势操作支持 #1446 @Sight-wcg
- #### table
- 修复 IE 下的报错问题 #1453 @Sight-wcg
- #### form
- 修复 `select` 在 IE10+ 中的兼容性问题 #1452 @Sight-wcg
- #### dropdown
- 增强 `delay` 选项,支持设置 显示/隐藏 的延迟时间 #1454 @Sight-wcg
### 下载: [layui-v2.9.2-rc.1.zip](https://gitee.com/layui/layui/attach_files/1615403/download)
---
<h2 id="2.9.1" class="ws-anchor">
2.9.1
<!-- <span class="layui-badge-rim" style="color: #16b777;">稳定版</span> -->
<span class="layui-badge-rim">2023-12-11</span>
</h2>

102
examples/introduce/test.html

@ -0,0 +1,102 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>测试 - Layui</title>
<link rel="stylesheet" href="layui/css/layui.css">
</head>
<body>
<div class="layui-container">
<div class="layui-progress" style="margin: 15px 0 30px;">
<div class="layui-progress-bar" lay-percent="100%"></div>
</div>
<div class="layui-btn-container">
<button class="layui-btn" test-active="test-form">一个按钮</button>
<button class="layui-btn layui-btn-normal" id="test2">当前日期</button>
</div>
<blockquote class="layui-elem-quote" style="margin-top: 30px;">
<div class="layui-text">
<ul>
<li>您当前预览的是:<span>Layui-v<span id="version"></span></span></li>
<li>Layui 是一套开源免费的 Web UI(界面)组件库。这是一个极其简洁的演示页面</li>
</ul>
</div>
</blockquote>
</div>
<!-- body 末尾处引入 layui -->
<script src="layui/layui.js"></script>
<script>
layui.use(function(){
var layer = layui.layer;
var form = layui.form;
var laydate = layui.laydate;
var util = layui.util;
// 欢迎信息
layer.msg('Hello World', {icon: 6});
// 输出版本号
lay('#version').html(layui.v);
// 日期
laydate.render({
elem: '#test2',
value: new Date(),
isInitValue: true
});
// 触发事件
util.on('test-active', {
'test-form': function(){
layer.open({
type: 1,
resize: false,
shadeClose: true,
area: '350px',
title: 'layer + form',
content: ['<ul class="layui-form layui-form-pane" style="margin: 15px;">',
'<li class="layui-form-item">',
'<label class="layui-form-label">输入框</label>',
'<div class="layui-input-block">',
'<input class="layui-input" lay-verify="required" name="field1">',
'</div>',
'</li>',
'<li class="layui-form-item">',
'<label class="layui-form-label">选择框</label>',
'<div class="layui-input-block">',
'<select name="field2">',
'<option value="A">A</option>',
'<option value="B">B</option>',
'<select>',
'</div>',
'</li>',
'<li class="layui-form-item" style="text-align:center;">',
'<button type="submit" lay-submit lay-filter="*" class="layui-btn">提交</button>',
'</li>',
'</ul>'].join(''),
success: function(layero, index){
layero.find('.layui-layer-content').css('overflow', 'visible');
form.render().on('submit(*)', function(data){
var field = data.field;
// 显示填写的表单
layer.msg(util.escape(JSON.stringify(field)), {
icon: 1
});
// layer.close(index); //关闭层
});
}
});
}
});
});
</script>
</body>
</html>

11
examples/introduce/免责声明.html

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>免责声明</title>
<script>location.href = 'https://gitee.com/layui/layui/blob/main/DISCLAIMER.md';</script>
</head>
<body>
</body>
</html>

11
examples/introduce/官方文档.html

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>官方文档</title>
<script>location.href = 'https://layui.github.io';</script>
</head>
<body>
</body>
</html>

3
gulpfile.js

@ -116,7 +116,8 @@ exports.release = gulp.series(
return gulp.src('./release/introduce/**/*')
.pipe(replace(/[^'"]+(\/layui\.css)/, 'layui/css$1')) // 替换 css 引入路径中的本地 path
.pipe(replace(/[^'"]+(\/layui\.js)/, 'layui$1')) // 替换 js 引入路径中的本地 path
.pipe(gulp.dest(rlsDirname));
.pipe(gulp.dest(rlsDirname)) // 用于本地
.pipe(gulp.dest('./examples/introduce')); // 用于 Github actions
},
exports.cp, // 复制 dist 目录文件
() => { // 生成 ZIP 压缩包

2
package.json

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

3
src/css/layui.css

@ -1520,7 +1520,8 @@ body .layui-util-face .layui-layer-content{padding:0; background-color:#fff; co
.layui-rate li{margin-top: 0 !important;}
.layui-rate li i.layui-icon{ font-size: 20px; color: #ffb800;}
.layui-rate li i.layui-icon{margin-right: 5px; transition: all .3s; -webkit-transition: all .3s;}
.layui-rate li i:hover{cursor: pointer; transform: scale(1.12); -webkit-transform: scale(1.12);}
.layui-rate li i:hover,
.layui-rate-hover{cursor: pointer; transform: scale(1.12); -webkit-transform: scale(1.12);}
.layui-rate[readonly] li i:hover{cursor: default; transform: scale(1);}
/** 颜色选择器 **/

2
src/layui.js vendored

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

18
src/modules/carousel.js

@ -331,14 +331,28 @@ layui.define(['jquery', 'lay'], function(exports){
if(options.elem.data('haveEvents')) return;
// 移入移出容器
options.elem.on('mouseenter', function(){
options.elem.on('mouseenter touchstart', function(){
if (that.config.autoplay === 'always') return;
clearInterval(that.timer);
}).on('mouseleave', function(){
}).on('mouseleave touchend', function(){
if (that.config.autoplay === 'always') return;
that.autoplay();
});
var touchEl = options.elem;
var isVertical = options.anim === 'updown';
lay.touchSwipe(touchEl, {
onTouchEnd: function(e, state){
var duration = Date.now() - state.timeStart;
var distance = isVertical ? state.distanceY : state.distanceX;
var speed = distance / duration;
var shouldSwipe = Math.abs(speed) > 0.25 || Math.abs(distance) > touchEl[isVertical ? 'height' : 'width']() / 3;
if(shouldSwipe){
that.slide(distance > 0 ? '' : 'sub');
}
}
})
options.elem.data('haveEvents', true);
};

26
src/modules/colorpicker.js

@ -567,6 +567,32 @@ layui.define(['jquery', 'lay'], function(exports){
change(hsb.h, hsb.s, hsb.b, a);
})
});
if(!lay.touchEventsSupported()) return;
// 触摸事件模拟
layui.each([
{elem: side, eventType: 'click'},
{elem: alphacolor, eventType: 'click'},
{elem: basis, eventType: 'mousedown'}
], function(i, obj){
lay.touchSwipe(obj.elem, {
onTouchMove: function(e){
touchHandler(e, obj.eventType)
}
})
})
function touchHandler(event, eventType) {
var pointer = event.touches[0];
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(eventType,
true, true, window, 1,
pointer.screenX, pointer.screenY,pointer.clientX, pointer.clientY,
false, false, false, false, 0, null
);
pointer.target.dispatchEvent(simulatedEvent);
}
};
//颜色选择器hsb转换

31
src/modules/dropdown.js

@ -101,7 +101,7 @@ layui.define(['jquery', 'laytpl', 'lay', 'util'], function(exports){
isAllowSpread: true, // 是否允许菜单组展开收缩
isSpreadItem: true, // 是否初始展开子菜单
data: [], // 菜单数据结构
delay: 300, // 延迟关闭的毫秒数,若 trigger 为 hover 时才生效
delay: [200, 300], // 延时显示或隐藏的毫秒数,若为 number 类型,则表示显示和隐藏的延迟时间相同,trigger 为 hover 时才生效
shade: 0, // 遮罩
accordion: false // 手风琴效果,仅菜单组生效。基础菜单需要在容器上追加 'lay-accordion' 属性。
};
@ -389,6 +389,17 @@ layui.define(['jquery', 'laytpl', 'lay', 'util'], function(exports){
lay('.' + STR_ELEM_SHADE).remove();
};
Class.prototype.normalizedDelay = function(){
var that = this;
var options = that.config;
var delay = [].concat(options.delay);
return {
show: delay[0],
hide: delay[1] !== undefined ? delay[1] : delay[0]
}
}
// 延迟删除视图
Class.prototype.delayRemove = function(){
var that = this;
@ -397,7 +408,7 @@ layui.define(['jquery', 'laytpl', 'lay', 'util'], function(exports){
thisModule.timer = setTimeout(function(){
that.remove();
}, options.delay);
}, that.normalizedDelay().hide);
};
// 事件
@ -411,12 +422,22 @@ layui.define(['jquery', 'laytpl', 'lay', 'util'], function(exports){
// 解除上一个事件
if(that.prevElem) that.prevElem.off(options.trigger, that.prevElemCallback);
// 是否鼠标移入时触发
var isMouseEnter = options.trigger === 'mouseenter';
// 记录被绑定的元素及回调
that.prevElem = options.elem;
that.prevElemCallback = function(e){
clearTimeout(thisModule.timer);
that.e = e;
that.render();
// 若为鼠标移入事件,则延迟触发
isMouseEnter ? (
thisModule.timer = setTimeout(function(){
that.render();
}, that.normalizedDelay().show)
) : that.render();
e.preventDefault();
};
@ -424,8 +445,8 @@ layui.define(['jquery', 'laytpl', 'lay', 'util'], function(exports){
options.elem.on(options.trigger, that.prevElemCallback);
// 如果是鼠标移入事件
if(options.trigger === 'mouseenter'){
// 行鼠标移出事件
if (isMouseEnter) {
// 行鼠标移出事件
options.elem.on('mouseleave', function(){
that.delayRemove();
});

7
src/modules/form.js

@ -626,7 +626,12 @@ layui.define(['lay', 'layer', 'util'], function(exports){
};
if(isSearch){
input.on('input propertychange', search).on('blur', function(e){
// #1449: IE10 和 11 中,带有占位符的 input 元素获得/失去焦点时,会触发 input 事件
var eventsType = 'input propertychange';
if(lay.ie && (lay.ie === '10' || lay.ie === '11') && input.attr('placeholder')){
eventsType = 'keyup';
}
input.on(eventsType, search).on('blur', function(e){
var selectedIndex = select[0].selectedIndex;
thatInput = input; // 当前的 select 中的 input 元素

109
src/modules/lay.js

@ -505,6 +505,115 @@
}
};
/**
* 检测是否支持 Passive Event Listeners
* 引用自 https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
* @type {boolean}
*/
lay.passiveSupported = function(){
var passiveSupported = false;
try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
passiveSupported = true;
}
});
window.addEventListener('test', null, opts);
window.removeEventListener('test', null, opts);
} catch (err) {}
return passiveSupported;
}();
/**
* 是否支持 touch 事件
*/
lay.touchEventsSupported = function(){
return 'ontouchstart' in window;
};
/**
* @typedef touchSwipeState
* @prop {{x: number,y: number}} pointerStart - 初始坐标
* @prop {{x: number,y: number}} pointerEnd - 结束坐标
* @prop {number} distanceX - X 轴移动距离
* @prop {number} distanceY - Y 轴移动距离
* @prop {'none'|'right'|'left'|'up'|'down'} direction - 滑动方向
* @prop {Date} timeStart 开始时间
*/
/**
* @callback touchSwipeCallback
* @param {TouchEvent} e 滑动事件
* @param {touchSwipeState} state 滑动相关的状态
*/
/**
* 基于 touch 事件的触摸滑动
* @param {string | HTMLElement | JQuery} elem - HTML 元素
* @param {{onTouchStart?: touchSwipeCallback, onTouchMove?: touchSwipeCallback, onTouchEnd?: touchSwipeCallback}} opts - 配置项
*/
lay.touchSwipe = function(elem, opts){
var options = opts
var targetElem = lay(elem)[0];
if(!targetElem || !lay.touchEventsSupported()) return;
var state = {
pointerStart: {x:0, y:0},
pointerEnd: {x:0, y:0},
distanceX: 0,
distanceY: 0,
direction:'none', // 'up','down','left','right','none
timeStart: null
}
var onStart = function(e){
if(e.touches.length !== 1) return;
bindEvents();
state.timeStart = Date.now();
state.pointerStart.x = state.pointerEnd.x = e.touches[0].clientX;
state.pointerStart.y = state.pointerEnd.y = e.touches[0].clientY;
options.onTouchStart && options.onTouchStart(e, state);
}
var onMove = function(e){
e.preventDefault();
state.pointerEnd.x = e.touches[0].clientX;
state.pointerEnd.y = e.touches[0].clientY;
state.distanceX = state.pointerStart.x - state.pointerEnd.x;
state.distanceY = state.pointerStart.y - state.pointerEnd.y;
if(Math.abs(state.distanceX) > Math.abs(state.distanceY)){
state.direction = state.distanceX > 0 ? 'left' : 'right';
}else{
state.direction = state.distanceY > 0 ? 'up' : 'down';
}
options.onTouchMove && options.onTouchMove(e, state);
}
var onEnd = function(e){
options.onTouchEnd && options.onTouchEnd(e, state);
unbindEvents();
}
var bindEvents = function(){
targetElem.addEventListener('touchmove', onMove, lay.passiveSupported ? { passive: false} : false);
targetElem.addEventListener('touchend', onEnd);
targetElem.addEventListener('touchcancel', onEnd);
}
var unbindEvents = function(){
targetElem.removeEventListener('touchmove', onMove);
targetElem.removeEventListener('touchend', onEnd, lay.passiveSupported ? { passive: false} : false);
targetElem.removeEventListener('touchcancel', onEnd);
}
// 防止事件重复绑定
if(targetElem.__lay_touchswipe_cb_){
targetElem.removeEventListener('touchstart', targetElem.__lay_touchswipe_cb_);
}
targetElem.__lay_touchswipe_cb_ = onStart;
targetElem.addEventListener('touchstart', onStart);
}
/*
* lay 元素操作

9
src/modules/laydate.js

@ -1514,7 +1514,8 @@
if(haveSpan[0]) haveSpan.remove();
elemHeader[2].appendChild(span);
lay(ul).find('ol').each(function(i){
var olElem = lay(ul).find('ol');
olElem.each(function(i){
var ol = this;
//选择时分秒
lay(ol).find('li').on('click', function(){
@ -1537,6 +1538,12 @@
that.setBtnStatus();
});
});
if(lay.touchEventsSupported()){
olElem.on('touchstart', function(){
this.style['overflow-y'] = 'auto';
})
}
}
return that;

24
src/modules/layer.js

@ -1604,6 +1604,28 @@ layer.photos = function(options, loop, key){
e.preventDefault();
});
// 滑动切换图片事件,仅限 layui 中
if(window.layui || window.lay){
var lay = window.layui.lay || window.lay;
var touchEndCallback = function(e, state){
var duration = Date.now() - state.timeStart;
var speed = state.distanceX / duration;
var threshold = win.width() / 3;
var shouldSwipe = Math.abs(speed) > 0.25 || Math.abs(state.distanceX) > threshold;
if(!shouldSwipe) return;
if(state.direction === 'left'){
dict.imgnext(true);
}else if(state.direction === 'right'){
dict.imgprev(true);
}
}
$.each([that.shadeo, dict.main], function(i, elem){
lay.touchSwipe(elem, {
onTouchEnd: touchEndCallback
})
})
}
};
// 图片预加载
@ -1764,7 +1786,7 @@ ready.run = function(_$){
// 加载方式
window.layui && layui.define ? (
layer.ready(),
layui.define('jquery', function(exports){ // layui
layui.define(['jquery','lay'], function(exports){ // layui
layer.path = layui.cache.dir;
ready.run(layui.$);

52
src/modules/rate.js

@ -155,8 +155,9 @@ layui.define(['jquery', 'lay'],function(exports){
var options = that.config;
var _ul = that.elemTemp;
var wide = _ul.find("i").width();
var liElems = _ul.children("li");
_ul.children("li").each(function(index){
liElems.each(function(index){
var ind = index + 1;
var othis = $(this);
@ -212,6 +213,55 @@ layui.define(['jquery', 'lay'],function(exports){
})
})
lay.touchSwipe(_ul, {
onTouchMove: function(e, state){
if(Date.now() - state.timeStart <= 200) return;
var pageX = e.touches[0].pageX;
var rateElemWidth = _ul.width();
var itemElemWidth = rateElemWidth / options.length; // 单颗星的宽度
var offsetX = pageX - _ul.offset().left;
var num = offsetX / itemElemWidth; // 原始值
var remainder = num % 1;
var integer = num - remainder;
// 最终值
var score = remainder <= 0.5 && options.half ? integer + 0.5 : Math.ceil(num);
if(score > options.length) score = options.length;
if(score < 0) score = 0;
liElems.each(function(index){
var iconElem = $(this).children('i');
var isActiveIcon = (Math.ceil(score) - index === 1);
var needSelect = Math.ceil(score) > index;
var shouldHalfIcon = (score - index === 0.5);
if(needSelect){
// 设置选中样式
iconElem.addClass(ICON_RATE_SOLID).removeClass(ICON_HALF_RATE);
if(options.half && shouldHalfIcon){
iconElem.addClass(ICON_RATE_HALF).removeClass(ICON_RATE_SOLID);
}
}else{
// 恢复初始样式
iconElem.addClass(ICON_RATE).removeClass(ICON_SOLID_HALF);
}
// 设置缩放样式
iconElem.toggleClass('layui-rate-hover', isActiveIcon);
});
// 更新最终值
options.value = score;
options.setText && options.setText(options.value);
},
onTouchEnd: function(e, state){
if(Date.now() - state.timeStart <= 200) return;
_ul.find('i').removeClass('layui-rate-hover');
options.choose && options.choose(options.value);
options.setText && options.setText(options.value);
}
});
};
//事件处理

147
src/modules/slider.js

@ -10,26 +10,26 @@ layui.define(['jquery', 'lay'], function(exports){
// 外部接口
var slider = {
config: {}
,index: layui.slider ? (layui.slider.index + 10000) : 0
config: {},
index: layui.slider ? (layui.slider.index + 10000) : 0,
// 设置全局项
,set: function(options){
set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
},
// 事件
,on: function(events, callback){
on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
};
// 操作当前实例
var thisSlider = function(){
var that = this
,options = that.config;
var that = this;
var options = that.config;
return {
setValue: function(value, index){ // 设置值
@ -37,8 +37,8 @@ layui.define(['jquery', 'lay'], function(exports){
value = value < options.min ? options.min : value;
options.value = value;
return that.slide('set', value, index || 0);
}
,config: options
},
config: options
}
};
@ -65,18 +65,18 @@ layui.define(['jquery', 'lay'], function(exports){
// 默认配置
Class.prototype.config = {
type: 'default' //滑块类型,垂直:vertical
,min: 0 //最小值
,max: 100 //最大值,默认100
,value: 0 //初始值,默认为0
,step: 1 //间隔值
,showstep: false //间隔点开启
,tips: true //文字提示,开启
,input: false //输入框,关闭
,range: false //范围选择,与输入框不能同时开启,默认关闭
,height: 200 //配合 type:"vertical" 使用,默认200px
,disabled: false //滑块禁用,默认关闭
,theme: '#16baaa' //主题颜色
type: 'default', //滑块类型,垂直:vertical
min: 0, //最小值
max: 100, //最大值,默认100
value: 0, //初始值,默认为0
step: 1, //间隔值
showstep: false, //间隔点开启
tips: true, //文字提示,开启
input: false, //输入框,关闭
range: false, //范围选择,与输入框不能同时开启,默认关闭
height: 200, //配合 type:"vertical" 使用,默认200px
disabled: false, //滑块禁用,默认关闭
theme: '#16baaa' //主题颜色
};
//滑块渲染
@ -116,9 +116,9 @@ layui.define(['jquery', 'lay'], function(exports){
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 + '%';
var scaleFir = Math.floor((options.value[0] - options.min) / (options.max - options.min) * 100);
var scaleSec = Math.floor((options.value[1] - options.min) / (options.max - options.min) * 100);
var scale = scaleSec - scaleFir + '%';
scaleFir = scaleFir + '%';
scaleSec = scaleSec + '%';
} else {
@ -143,8 +143,8 @@ layui.define(['jquery', 'lay'], function(exports){
'<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);
var othis = $(options.elem);
var hasRender = othis.next('.' + ELEM_VIEW);
//生成替代元素
hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender
that.elemTemp = $(temp);
@ -204,12 +204,12 @@ layui.define(['jquery', 'lay'], function(exports){
//划过滑块显示数值
var timer;
that.elemTemp.find('.' + SLIDER_WRAP_BTN).on('mouseover', function(){
var sliderWidth = options.type === 'vertical' ? options.height : that.elemTemp[0].offsetWidth
,sliderWrap = that.elemTemp.find('.' + SLIDER_WRAP)
,tipsLeft = options.type === 'vertical' ? (sliderWidth - $(this).parent()[0].offsetTop - sliderWrap.height()) : $(this).parent()[0].offsetLeft
,left = tipsLeft / sliderWidth * 100
,value = $(this).parent().data('value')
,tipsTxt = options.setTips ? options.setTips(value) : value;
var sliderWidth = options.type === 'vertical' ? options.height : that.elemTemp[0].offsetWidth;
var sliderWrap = that.elemTemp.find('.' + SLIDER_WRAP);
var tipsLeft = options.type === 'vertical' ? (sliderWidth - $(this).parent()[0].offsetTop - sliderWrap.height()) : $(this).parent()[0].offsetLeft;
var left = tipsLeft / sliderWidth * 100;
var value = $(this).parent().data('value');
var tipsTxt = options.setTips ? options.setTips(value) : value;
that.elemTemp.find('.' + SLIDER_TIPS).html(tipsTxt);
clearTimeout(timer);
@ -235,17 +235,17 @@ layui.define(['jquery', 'lay'], function(exports){
//滑块滑动
Class.prototype.slide = function(setValue, value, i){
var that = this
,options = that.config
,sliderAct = that.elemTemp
,sliderWidth = function(){
var that = this;
var options = that.config;
var sliderAct = that.elemTemp;
var sliderWidth = function(){
return options.type === 'vertical' ? options.height : sliderAct[0].offsetWidth
}
,sliderWrap = sliderAct.find('.' + SLIDER_WRAP)
,sliderTxt = sliderAct.next('.' + SLIDER_INPUT)
,inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val()
,step = 100 / ((options.max - options.min) / Math.ceil(options.step))
,change = function(offsetValue, index, from){
};
var sliderWrap = sliderAct.find('.' + SLIDER_WRAP);
var sliderTxt = sliderAct.next('.' + SLIDER_INPUT);
var inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val();
var step = 100 / ((options.max - options.min) / Math.ceil(options.step));
var change = function(offsetValue, index, from){
if(Math.ceil(offsetValue) * step > 100){
offsetValue = Math.ceil(offsetValue) * step
}else{
@ -254,8 +254,8 @@ layui.define(['jquery', 'lay'], function(exports){
offsetValue = offsetValue > 100 ? 100: offsetValue;
offsetValue = offsetValue < 0 ? 0: offsetValue;
sliderWrap.eq(index).css((options.type === 'vertical' ?'bottom':'left'), offsetValue + '%');
var firLeft = valueTo(sliderWrap[0].offsetLeft)
,secLeft = options.range ? valueTo(sliderWrap[1].offsetLeft) : 0;
var firLeft = valueTo(sliderWrap[0].offsetLeft);
var secLeft = options.range ? valueTo(sliderWrap[1].offsetLeft) : 0;
if(options.type === 'vertical'){
sliderAct.find('.' + SLIDER_TIPS).css({"bottom":offsetValue + '%', "margin-bottom":"20px"});
firLeft = valueTo(sliderWidth() - sliderWrap[0].offsetTop - sliderWrap.height());
@ -281,8 +281,8 @@ layui.define(['jquery', 'lay'], function(exports){
//如果开启范围选择,则返回数组值
if(options.range){
var arrValue = [
sliderWrap.eq(0).data('value')
,sliderWrap.eq(1).data('value')
sliderWrap.eq(0).data('value'),
sliderWrap.eq(1).data('value')
];
if(arrValue[0] > arrValue[1]) arrValue.reverse(); //如果前面的圆点超过了后面的圆点值,则调换顺序
}
@ -292,27 +292,40 @@ layui.define(['jquery', 'lay'], function(exports){
// 值完成选中的事件
if(from === 'done') options.done && options.done(that.value);
}
,valueTo = function(value){
var oldLeft = value / sliderWidth() * 100 / step
,left = Math.round(oldLeft) * step;
};
var valueTo = function(value){
var oldLeft = value / sliderWidth() * 100 / step;
var 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){
var elemMove = $(['<div class="layui-auxiliar-moving" id="LAY-slider-moving"></div'].join(''));
var createMoveElem = function(sliderBtnElem, move, up){
var upCall = function(){
up && up();
// 移动端延时一秒关闭
up && up(lay.touchEventsSupported() ? 1000 : 0);
elemMove.remove();
options.done && options.done(that.value);
// 移动端
if (lay.touchEventsSupported()) {
sliderBtnElem[0].removeEventListener('touchmove', move, lay.passiveSupported ? { passive: false } : false);
sliderBtnElem[0].removeEventListener('touchend', upCall);
sliderBtnElem[0].removeEventListener('touchcancel', upCall);
}
};
$('#LAY-slider-moving')[0] || $('body').append(elemMove);
elemMove.on('mousemove', move);
elemMove.on('mouseup', upCall).on('mouseleave', upCall);
// 移动端
if (lay.touchEventsSupported()) {
sliderBtnElem[0].addEventListener('touchmove', move, lay.passiveSupported ? { passive: false } : false);
sliderBtnElem[0].addEventListener('touchend', upCall);
sliderBtnElem[0].addEventListener('touchcancel', upCall);
}
};
//动态赋值
@ -321,11 +334,15 @@ layui.define(['jquery', 'lay'], function(exports){
//滑块滑动
sliderAct.find('.' + SLIDER_WRAP_BTN).each(function(index){
var othis = $(this);
othis.on('mousedown', function(e){
othis.on('mousedown touchstart', function(e){
e = e || window.event;
if(e.type === 'touchstart'){
e.clientX = e.originalEvent.touches[0].clientX;
e.clientY = e.originalEvent.touches[0].clientY;
}
var oldleft = othis.parent()[0].offsetLeft
,oldx = e.clientX;
var oldleft = othis.parent()[0].offsetLeft;
var oldx = e.clientX;
if(options.type === 'vertical'){
oldleft = sliderWidth() - othis.parent()[0].offsetTop - sliderWrap.height()
oldx = e.clientY;
@ -333,6 +350,10 @@ layui.define(['jquery', 'lay'], function(exports){
var move = function(e){
e = e || window.event;
if (e.type === 'touchmove') {
e.clientX = e.touches[0].clientX;
e.clientY = e.touches[0].clientY;
}
var left = oldleft + (options.type === 'vertical' ? (oldx - e.clientY) : (e.clientX - oldx));
if(left < 0)left = 0;
if(left > sliderWidth())left = sliderWidth();
@ -343,12 +364,14 @@ layui.define(['jquery', 'lay'], function(exports){
e.preventDefault();
};
var up = function(){
var up = function(delay){
othis.removeClass(ELEM_HOVER);
sliderAct.find('.' + SLIDER_TIPS).hide();
setTimeout(function(){
sliderAct.find('.' + SLIDER_TIPS).hide();
}, delay);
};
createMoveElem(move, up)
createMoveElem(othis, move, up)
});
});
@ -417,8 +440,8 @@ layui.define(['jquery', 'lay'], function(exports){
//事件处理
Class.prototype.events = function(){
var that = this
,options = that.config;
var that = this;
var options = that.config;
};
//核心入口

4
src/modules/table.js

@ -82,7 +82,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
var resolveTplStr = function(templet){
try{
return lay(templet).html();
}catch{
}catch(err){
return templet;
}
}
@ -558,7 +558,7 @@ layui.define(['lay', 'laytpl', 'laypage', 'form', 'util'], function(exports){
layui.each(options.cols, function(i1, item1) {
layui.each(item1, function(i2, item2) {
var key = [index, i1, i2].join('-');
var val = item2.width ? ['width: ', item2.width, 'px'].join('') : '';
var val = ['width: ', (item2.width || options.cellMinWidth), 'px'].join('');
text.push('.laytable-cell-'+ key +'{'+ val +'}');
});
});

Loading…
Cancel
Save