升级.net8
This commit is contained in:
@ -3,15 +3,18 @@
|
||||
|
||||
;!function(window){ // gulp build: lay-header
|
||||
"use strict";
|
||||
|
||||
|
||||
var MOD_NAME = 'lay'; // 模块名
|
||||
var document = window.document;
|
||||
|
||||
// 元素查找
|
||||
var lay = function(selector){
|
||||
|
||||
/**
|
||||
* 元素查找
|
||||
* @param {string | HTMLElement | JQuery} selector
|
||||
*/
|
||||
var lay = function(selector){
|
||||
return new Class(selector);
|
||||
};
|
||||
|
||||
|
||||
// 构造器
|
||||
var Class = function(selector){
|
||||
var that = this;
|
||||
@ -27,15 +30,37 @@
|
||||
that.push(elem[index]);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* API 兼容
|
||||
*/
|
||||
Array.prototype.indexOf = Array.prototype.indexOf || function(searchElement, fromIndex) {
|
||||
var rst = -1;
|
||||
fromIndex = fromIndex || 0;
|
||||
layui.each(this, function(index, val){
|
||||
if (searchElement === val && index >= fromIndex) {
|
||||
rst = index;
|
||||
return !0;
|
||||
}
|
||||
});
|
||||
return rst;
|
||||
};
|
||||
|
||||
/*
|
||||
lay 对象操作
|
||||
*/
|
||||
|
||||
|
||||
Class.fn = Class.prototype = [];
|
||||
Class.fn.constructor = Class;
|
||||
|
||||
// 普通对象深度扩展
|
||||
|
||||
/**
|
||||
* 将两个或多个对象的内容深度合并到第一个对象中
|
||||
* @callback ExtendFunc
|
||||
* @param {*} target - 一个对象
|
||||
* @param {...*} objectN - 包含额外的属性合并到第一个参数
|
||||
* @returns {*} 返回合并后的对象
|
||||
*/
|
||||
/** @type ExtendFunc*/
|
||||
lay.extend = function(){
|
||||
var ai = 1;
|
||||
var length;
|
||||
@ -61,20 +86,23 @@
|
||||
}
|
||||
return args[0];
|
||||
};
|
||||
|
||||
// ie 版本
|
||||
|
||||
/**
|
||||
* IE 版本
|
||||
* @type {string | boolean} - 如果是 IE 返回版本字符串,否则返回 false
|
||||
*/
|
||||
lay.ie = function(){
|
||||
var agent = navigator.userAgent.toLowerCase();
|
||||
return (!!window.ActiveXObject || "ActiveXObject" in window) ? (
|
||||
(agent.match(/msie\s(\d+)/) || [])[1] || '11' // 由于 ie11 并没有 msie 的标识
|
||||
) : false;
|
||||
}();
|
||||
|
||||
|
||||
/**
|
||||
|
||||
|
||||
/**
|
||||
* 获取 layui 常见方法,以便用于组件单独版
|
||||
*/
|
||||
|
||||
|
||||
lay.layui = layui || {};
|
||||
lay.getPath = layui.cache.dir; // 获取当前 JS 所在目录
|
||||
lay.stope = layui.stope; // 中止冒泡
|
||||
@ -83,8 +111,18 @@
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
// 数字前置补零
|
||||
|
||||
/**
|
||||
* 数字前置补零
|
||||
* @param {number | string} num - 原始数字
|
||||
* @param {number} [length=2] - 数字长度,如果原始数字长度小于 length,则前面补零
|
||||
* @returns {string} 返回补 0 后的数字
|
||||
* @example
|
||||
* ```js
|
||||
* lay.digit(6, 2); // "06"
|
||||
* lay.digit('7', 3); // "007"
|
||||
* ```
|
||||
*/
|
||||
lay.digit = function(num, length){
|
||||
if(!(typeof num === 'string' || typeof num === 'number')) return '';
|
||||
|
||||
@ -96,8 +134,17 @@
|
||||
}
|
||||
return num < Math.pow(10, length) ? str + num : num;
|
||||
};
|
||||
|
||||
// 创建元素
|
||||
|
||||
/**
|
||||
* 创建元素
|
||||
* @param {string} elemName - 元素的标签名
|
||||
* @param {Object.<string, string>} [attr] - 添加到元素上的属性
|
||||
* @returns {HTMLElement} 返回创建的 HTML 元素
|
||||
* @example
|
||||
* ```js
|
||||
* lay.elem('div', {id: 'test'}) // <div id="test"></div>
|
||||
* ```
|
||||
*/
|
||||
lay.elem = function(elemName, attr){
|
||||
var elem = document.createElement(elemName);
|
||||
lay.each(attr || {}, function(key, value){
|
||||
@ -106,50 +153,184 @@
|
||||
return elem;
|
||||
};
|
||||
|
||||
// 当前页面是否存在滚动条
|
||||
/**
|
||||
* 当前页面是否存在滚动条
|
||||
* @returns {boolean} 是否存在滚动条
|
||||
* @example
|
||||
* ```
|
||||
* lay.hasScrollbar() // true 或 false
|
||||
* ```
|
||||
*/
|
||||
lay.hasScrollbar = function(){
|
||||
return document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight);
|
||||
};
|
||||
|
||||
// 元素定位
|
||||
lay.position = function(elem, elemView, obj){
|
||||
if(!elemView) return;
|
||||
obj = obj || {};
|
||||
|
||||
|
||||
/**
|
||||
* 获取 style rules
|
||||
* @param {HTMLStyleElement} style - HTMLStyle 元素
|
||||
* @param {(ruleItem: CSSStyleRule, index: number) => boolean} [callback] - 用来返回 style 元素中的每个 `style rule` 的函数,返回 true 终止遍历
|
||||
* @returns {CSSRuleList } 返回 `style rules`
|
||||
* @example
|
||||
* ```
|
||||
* <style id="test">
|
||||
* .lay-card{
|
||||
* color: #000;
|
||||
* }
|
||||
* .lay-btn-success{
|
||||
* color: green;
|
||||
* }
|
||||
* </style>
|
||||
*
|
||||
* lay.getStyleRules($('#test')[0], function(rule, index){
|
||||
* if(rule.selectorText === '.lay-card'){
|
||||
* console.log(index, rule.cssText) // 0 '.lay-card{color: #000}'
|
||||
* rule.style.color = '#EEE';
|
||||
* return true; // 终止遍历
|
||||
* }
|
||||
* }) // RuleList
|
||||
* ```
|
||||
*/
|
||||
lay.getStyleRules = function(style, callback) {
|
||||
if (!style) return;
|
||||
|
||||
var sheet = style.sheet || style.styleSheet || {};
|
||||
var rules = sheet.cssRules || sheet.rules;
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
layui.each(rules, function(i, item){
|
||||
if (callback(item, i)) return true;
|
||||
});
|
||||
}
|
||||
|
||||
return rules;
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建 style 样式
|
||||
* @param {Object} options - 可配置的选项
|
||||
* @param {string | HTMLElement | JQuery} [options.target] - 目标容器,指定后会将样式追加到目标容器
|
||||
* @param {string} [options.id] - 样式元素的 id,默认自增
|
||||
* @param {string} options.text - 样式内容
|
||||
* @returns {HTMLStyleElement} 返回创建的样式元素
|
||||
* @example
|
||||
* ```html
|
||||
* <div id="targetEl">
|
||||
* <!-- 样式追加到目标容器 -->
|
||||
* <style id="LAY-STYLE-DF-0">.card{color: #000}</style>
|
||||
* </div>
|
||||
*
|
||||
* lay.style({
|
||||
* target: '#targetEl',
|
||||
* text: '.card{color: #000}'
|
||||
* }) // <style id="LAY-STYLE-DF-0">.card{color: #000}</style>
|
||||
* ```
|
||||
*/
|
||||
lay.style = function(options){
|
||||
options = options || {};
|
||||
|
||||
var style = lay.elem('style');
|
||||
var styleText = options.text || '';
|
||||
var target = options.target;
|
||||
|
||||
if (!styleText) return;
|
||||
|
||||
// 添加样式
|
||||
if ('styleSheet' in style) {
|
||||
style.setAttribute('type', 'text/css');
|
||||
style.styleSheet.cssText = styleText;
|
||||
} else {
|
||||
style.innerHTML = styleText;
|
||||
}
|
||||
|
||||
// ID
|
||||
style.id = 'LAY-STYLE-'+ (options.id || function(index) {
|
||||
lay.style.index++;
|
||||
return 'DF-'+ index;
|
||||
}(lay.style.index || 0));
|
||||
|
||||
// 是否向目标容器中追加 style 元素
|
||||
if (target) {
|
||||
var styleElem = lay(target).find('#'+ style.id);
|
||||
styleElem[0] && styleElem.remove();
|
||||
lay(target).append(style);
|
||||
}
|
||||
|
||||
return style;
|
||||
};
|
||||
|
||||
/**
|
||||
* 将元素定位到指定目标元素附近
|
||||
* @param {HTMLElement} target - 目标元素
|
||||
* @param {HTMLElement} elem - 定位元素
|
||||
* @param {Object} [opts] - 可配置的选项
|
||||
* @param {'absolute' | 'fixed'} [opts.position] - 元素的定位类型
|
||||
* @param {'left' | 'right'} [opts.clickType="left"] - 点击类型,默认为 'left',如果 {@link target} 是 document 或 body 元素,则为 'right'
|
||||
* @param {'left' | 'right' | 'center'} [opts.align="left"] - 对齐方式
|
||||
* @param {boolean} [opts.allowBottomOut=false] - 顶部没有足够区域显示时,是否允许底部溢出
|
||||
* @param {string | number} [opts.margin=5] - 边距
|
||||
* @param {Event} [opts.e] - 事件对象,仅右键生效
|
||||
* @param {boolean} [opts.SYSTEM_RELOAD] - 是否重载,用于出现滚动条时重新计算位置
|
||||
* @param {[offsetX:number, offsetY:number]} [opts.offset] - 相对于触发元素的额外偏移量[x,y]
|
||||
* @example
|
||||
* ```js
|
||||
* <button id="targetEl">dropdown</button>
|
||||
* <ul id="contentEl" class="dropdown-menu">
|
||||
* <li>菜单1</li>
|
||||
* <li>菜单2</li>
|
||||
* </ul>
|
||||
*
|
||||
* // 下拉菜单将被定位到按钮附近
|
||||
* lay.position(
|
||||
* $('#targetEl')[0],
|
||||
* $('#contentEl')[0],
|
||||
* {
|
||||
* position: 'fixed',
|
||||
* align: 'center'
|
||||
* }
|
||||
* )
|
||||
* ```
|
||||
*/
|
||||
lay.position = function(target, elem, opts){
|
||||
if(!elem) return;
|
||||
opts = opts || {};
|
||||
|
||||
// 如果绑定的是 document 或 body 元素,则直接获取鼠标坐标
|
||||
if(elem === document || elem === lay('body')[0]){
|
||||
obj.clickType = 'right';
|
||||
if(target === document || target === lay('body')[0]){
|
||||
opts.clickType = 'right';
|
||||
}
|
||||
|
||||
// 绑定绑定元素的坐标
|
||||
var rect = obj.clickType === 'right' ? function(){
|
||||
var e = obj.e || window.event || {};
|
||||
var rect = opts.clickType === 'right' ? function(){
|
||||
var e = opts.e || window.event || {};
|
||||
return {
|
||||
left: e.clientX
|
||||
,top: e.clientY
|
||||
,right: e.clientX
|
||||
,bottom: e.clientY
|
||||
left: e.clientX,
|
||||
top: e.clientY,
|
||||
right: e.clientX,
|
||||
bottom: e.clientY
|
||||
}
|
||||
}() : elem.getBoundingClientRect()
|
||||
,elemWidth = elemView.offsetWidth // 控件的宽度
|
||||
,elemHeight = elemView.offsetHeight // 控件的高度
|
||||
|
||||
}() : target.getBoundingClientRect();
|
||||
var elemWidth = elem.offsetWidth; // 控件的宽度
|
||||
var elemHeight = elem.offsetHeight; // 控件的高度
|
||||
|
||||
// 滚动条高度
|
||||
,scrollArea = function(type){
|
||||
var scrollArea = function(type){
|
||||
type = type ? 'scrollLeft' : 'scrollTop';
|
||||
return document.body[type] | document.documentElement[type];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// 窗口宽高
|
||||
,winArea = function(type){
|
||||
var winArea = function(type){
|
||||
return document.documentElement[type ? 'clientWidth' : 'clientHeight']
|
||||
}, margin = 5, left = rect.left, top = rect.bottom;
|
||||
|
||||
};
|
||||
var margin = 'margin' in opts ? opts.margin : 5;
|
||||
var left = rect.left;
|
||||
var top = rect.bottom;
|
||||
|
||||
// 相对元素居中
|
||||
if(obj.align === 'center'){
|
||||
left = left - (elemWidth - elem.offsetWidth)/2;
|
||||
} else if(obj.align === 'right'){
|
||||
left = left - elemWidth + elem.offsetWidth;
|
||||
if(opts.align === 'center'){
|
||||
left = left - (elemWidth - target.offsetWidth) / 2;
|
||||
} else if(opts.align === 'right'){
|
||||
left = left - elemWidth + target.offsetWidth;
|
||||
}
|
||||
|
||||
// 判断右侧是否超出边界
|
||||
@ -158,8 +339,19 @@
|
||||
}
|
||||
// 左侧是否超出边界
|
||||
if(left < margin) left = margin;
|
||||
|
||||
|
||||
|
||||
// 判断底部和顶部是否超出边界
|
||||
if(rect.bottom + elemHeight + margin > winArea()){ // 底部超出边界
|
||||
// 优先判断顶部是否有足够区域显示完全,且底部不能超出边界
|
||||
if(rect.top > elemHeight + margin && rect.top <= winArea() ){
|
||||
top = rect.top - elemHeight - margin*2; // 顶部有足够的区域显示
|
||||
} else if(!opts.allowBottomOut){ // 顶部没有足够区域显示时,是否允许底部溢出
|
||||
top = winArea() - elemHeight - margin*2; // 面板向底部靠齐
|
||||
if(top < 0) top = 0; // 如果面板底部靠齐时,又溢出窗口顶部,则只能将顶部靠齐
|
||||
}
|
||||
}
|
||||
/*
|
||||
if(top + elemHeight + margin > winArea()){
|
||||
// 优先顶部是否有足够区域显示完全
|
||||
if(rect.top > elemHeight + margin){
|
||||
@ -174,29 +366,50 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// 定位类型
|
||||
var position = obj.position;
|
||||
if(position) elemView.style.position = position;
|
||||
|
||||
var position = opts.position;
|
||||
if(position) elem.style.position = position;
|
||||
var offsetX = opts.offset ? opts.offset[0] : 0;
|
||||
var offsetY = opts.offset ? opts.offset[1] : 0;
|
||||
|
||||
// 设置坐标
|
||||
elemView.style.left = left + (position === 'fixed' ? 0 : scrollArea(1)) + 'px';
|
||||
elemView.style.top = top + (position === 'fixed' ? 0 : scrollArea()) + 'px';
|
||||
elem.style.left = left + (position === 'fixed' ? 0 : scrollArea(1)) + offsetX + 'px';
|
||||
elem.style.top = top + (position === 'fixed' ? 0 : scrollArea()) + offsetY + 'px';
|
||||
|
||||
// 防止页面无滚动条时,又因为弹出面板而出现滚动条导致的坐标计算偏差
|
||||
if(!lay.hasScrollbar()){
|
||||
var rect1 = elemView.getBoundingClientRect();
|
||||
var rect1 = elem.getBoundingClientRect();
|
||||
// 如果弹出面板的溢出窗口底部,则表示将出现滚动条,此时需要重新计算坐标
|
||||
if(!obj.SYSTEM_RELOAD && (rect1.bottom + margin) > winArea()){
|
||||
obj.SYSTEM_RELOAD = true;
|
||||
if(!opts.SYSTEM_RELOAD && (rect1.bottom + margin) > winArea()){
|
||||
opts.SYSTEM_RELOAD = true;
|
||||
setTimeout(function(){
|
||||
lay.position(elem, elemView, obj);
|
||||
lay.position(target, elem, opts);
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 获取元素上的属性配置项
|
||||
|
||||
/**
|
||||
* 获取元素上的属性配置项
|
||||
* @param {string | HTMLElement | JQuery} elem - HTML 元素
|
||||
* @param {{attr: string} | string} [opts="lay-options"] - 可配置的选项,string 类型指定属性名
|
||||
* @returns {Object.<string, any>} 返回元素上的属性配置项
|
||||
* @example
|
||||
* ```js
|
||||
* <div id="testEl" lay-options="{color:red}" lay-toc="{hot: true}"></div>
|
||||
*
|
||||
* var elem = $('#testEl')
|
||||
* lay.options(elem) // {color:red}
|
||||
* lay.options(elem[0]) // {color:red}
|
||||
* lay.options('#testEl') // {color:red}
|
||||
* lay.options('#testEl', {attr: 'lay-toc'}) // {hot: true}
|
||||
* lay.options('#testEl', 'lay-toc') // {hot: true}
|
||||
*
|
||||
* $('#testEl').attr('lay-toc') // '{hot: true}'
|
||||
* ```
|
||||
*/
|
||||
lay.options = function(elem, opts){
|
||||
opts = typeof opts === 'object' ? opts : {attr: opts};
|
||||
|
||||
@ -207,17 +420,30 @@
|
||||
var attrValue = othis.attr(attrName);
|
||||
|
||||
try {
|
||||
/**
|
||||
* 请注意: 开发者在使用 lay-options="{}" 配置组件选项时,需确保属性值不来自于网页用户,
|
||||
* 即属性值必须在网页开发者自身的可控范围内,否则请勿在 HTML 标签属性中获取组件选项。
|
||||
*/
|
||||
return new Function('return '+ (attrValue || '{}'))();
|
||||
} catch(ev) {
|
||||
layui.hint().error(opts.errorText || [
|
||||
attrName + '="'+ attrValue + '"',
|
||||
attrName + '="'+ attrValue + '"',
|
||||
'\n parseerror: '+ ev
|
||||
].join('\n'), 'error');
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// 元素是否属于顶级元素(document 或 body)
|
||||
|
||||
|
||||
/**
|
||||
* 元素是否属于顶级元素(document 或 body)
|
||||
* @param {HTMLElement} elem - HTML 元素
|
||||
* @returns {boolean} 是否属于顶级元素
|
||||
* @example
|
||||
* ```js
|
||||
* lay.isTopElem(document) // true
|
||||
* ```
|
||||
*/
|
||||
lay.isTopElem = function(elem){
|
||||
var topElems = [document, lay('body')[0]]
|
||||
,matched = false;
|
||||
@ -229,11 +455,328 @@
|
||||
return matched;
|
||||
};
|
||||
|
||||
// 剪切板
|
||||
lay.clipboard = {
|
||||
/**
|
||||
* 写入文本
|
||||
* @param {Object} options - 可配置的选项
|
||||
* @param {string} options.text - 写入剪贴板的文本
|
||||
* @param {() => void} [options.done] - 写入成功/完成回调
|
||||
* @param {(err?: any) => void} [options.error] - 写入失败回调
|
||||
* @example
|
||||
* ```js
|
||||
* lay.clipboard.writeText({
|
||||
* text: '测试文本',
|
||||
* done: function(){ layer.msg('copied')},
|
||||
* error: function(){ layer.msg('error')}
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
writeText: function(options) {
|
||||
var text = String(options.text);
|
||||
|
||||
if(navigator && 'clipboard' in navigator){
|
||||
navigator.clipboard.writeText(text)
|
||||
.then(options.done, function(){
|
||||
legacyCopy();
|
||||
});
|
||||
}else{
|
||||
legacyCopy();
|
||||
}
|
||||
|
||||
function legacyCopy(){
|
||||
var elem = document.createElement('textarea');
|
||||
|
||||
elem.value = text;
|
||||
elem.style.position = 'fixed';
|
||||
elem.style.opacity = '0';
|
||||
elem.style.top = '0px';
|
||||
elem.style.left = '0px';
|
||||
|
||||
document.body.appendChild(elem);
|
||||
elem.select();
|
||||
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
typeof options.done === 'function' && options.done();
|
||||
} catch(err) {
|
||||
typeof options.error === 'function' && options.error(err);
|
||||
} finally {
|
||||
elem.remove ? elem.remove() : document.body.removeChild(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 检测是否支持 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;
|
||||
state.distanceX = state.distanceY = 0;
|
||||
state.direction = 'none'
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/** @type {(elem: Element|Document|Window,eventName: string,fn:EventListenerOrEventListenerObject,options: boolean | AddEventListenerOptions) => any}*/
|
||||
lay.addEvent = function(){
|
||||
if(document.addEventListener){
|
||||
return function(elem, eventName, fn, options){
|
||||
elem.addEventListener(eventName, fn, options);
|
||||
}
|
||||
}else{
|
||||
return function(elem, eventName, fn){
|
||||
var prefix = '_lay_on_';
|
||||
var eventsCacheName = prefix + eventName;
|
||||
var listener = function(e){
|
||||
e.target = e.srcElement;
|
||||
fn.call(elem, e);
|
||||
}
|
||||
listener._rawFn = fn;
|
||||
if(!elem[eventsCacheName]){
|
||||
elem[eventsCacheName] = [];
|
||||
}
|
||||
var include = false;
|
||||
lay.each(elem[eventsCacheName], function(_, listener){
|
||||
if(listener._rawFn === fn){
|
||||
include = true;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
if(!include){
|
||||
elem[eventsCacheName].push(listener);
|
||||
elem.attachEvent('on' + eventName, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
||||
/** @type {(elem: Element|Document|Window,eventName: string,fn:EventListenerOrEventListenerObject,options: boolean | EventListenerOptions) => any}*/
|
||||
lay.removeEvent = function(){
|
||||
if(document.removeEventListener){
|
||||
return function(elem, eventName, fn, options){
|
||||
elem.removeEventListener(eventName, fn, options);
|
||||
}
|
||||
}else{
|
||||
return function(elem, eventName, fn){
|
||||
var prefix = '_lay_on_';
|
||||
var eventsCacheName = prefix + eventName;
|
||||
var events = elem[eventsCacheName];
|
||||
if(layui.isArray(events)){
|
||||
var newEvents = [];
|
||||
lay.each(events, function(_, listener){
|
||||
if(listener._rawFn === fn){
|
||||
elem.detachEvent('on'+ eventName, listener);
|
||||
}else{
|
||||
newEvents.push(listener);
|
||||
}
|
||||
})
|
||||
elem[eventsCacheName] = newEvents;
|
||||
}
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
||||
/**
|
||||
* 监听指定元素外部的点击
|
||||
* @param {HTMLElement} target - 被监听的元素
|
||||
* @param {(e: Event) => void} handler - 事件触发时执行的函数
|
||||
* @param {object} [options] - 选项
|
||||
* @param {string} [options.event="pointerdown"] - 监听的事件类型
|
||||
* @param {HTMLElement | Window} [options.scope=document] - 监听范围
|
||||
* @param {Array<HTMLElement | string>} [options.ignore] - 忽略监听的元素或选择器字符串
|
||||
* @param {boolean} [options.capture=true] - 对内部事件侦听器使用捕获阶段
|
||||
* @returns {() => void} - 返回一个停止事件监听的函数
|
||||
*/
|
||||
lay.onClickOutside = function(target, handler, options){
|
||||
options = options || {};
|
||||
var eventType = options.event || ('onpointerdown' in window ? 'pointerdown' : 'mousedown');
|
||||
var scopeTarget = options.scope || document;
|
||||
var ignore = options.ignore || [];
|
||||
var useCapture = 'capture' in options ? options.capture : true;
|
||||
|
||||
var listener = function(event){
|
||||
var el = target;
|
||||
var eventTarget = event.target || event.srcElement;
|
||||
var eventPath = getEventPath(event);
|
||||
|
||||
if (!el || el === eventTarget || eventPath.indexOf(el) !== -1){
|
||||
return;
|
||||
}
|
||||
if(shouldIgnore(event, eventPath)){
|
||||
return;
|
||||
}
|
||||
|
||||
handler(event);
|
||||
};
|
||||
|
||||
function shouldIgnore(event, eventPath){
|
||||
var eventTarget = event.target || event.srcElement;
|
||||
for(var i = 0; i < ignore.length; i++){
|
||||
var target = ignore[i];
|
||||
if(typeof target === 'string'){
|
||||
var targetElements = document.querySelectorAll(target);
|
||||
for(var j = 0; j < targetElements.length; j++){
|
||||
var targetEl = targetElements[i];
|
||||
if(targetEl === eventTarget || eventPath.indexOf(targetEl) !== -1){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(target && (target === eventTarget || eventPath.indexOf(target) !== -1)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEventPath(event){
|
||||
var path = (event.composedPath && event.composedPath()) || event.path;
|
||||
var eventTarget = event.target || event.srcElement;
|
||||
|
||||
if (path !== null && path !== undefined){
|
||||
return path;
|
||||
}
|
||||
|
||||
function getParents(node, memo){
|
||||
memo = memo || [];
|
||||
var parentNode = node.parentNode;
|
||||
|
||||
return parentNode
|
||||
? getParents(parentNode, memo.concat([parentNode]))
|
||||
: memo;
|
||||
}
|
||||
|
||||
return [eventTarget].concat(getParents(eventTarget));
|
||||
}
|
||||
|
||||
function bindEventListener(elem, eventName, handler, opts){
|
||||
elem.addEventListener
|
||||
? elem.addEventListener(eventName, handler, opts)
|
||||
: elem.attachEvent('on' + eventName, handler);
|
||||
|
||||
return function(){
|
||||
elem.removeEventListener
|
||||
? elem.removeEventListener(eventName, handler, opts)
|
||||
: elem.detachEvent('on' + eventName, handler);
|
||||
}
|
||||
}
|
||||
|
||||
return bindEventListener(
|
||||
scopeTarget,
|
||||
eventType,
|
||||
listener,
|
||||
lay.passiveSupported ? { passive: true, capture: useCapture } : useCapture
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* lay 元素操作
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// 追加字符
|
||||
Class.addStr = function(str, new_str){
|
||||
@ -246,7 +789,7 @@
|
||||
});
|
||||
return str.replace(/^\s|\s$/, '');
|
||||
};
|
||||
|
||||
|
||||
// 移除值
|
||||
Class.removeStr = function(str, new_str){
|
||||
str = str.replace(/\s+/, ' ');
|
||||
@ -259,7 +802,7 @@
|
||||
});
|
||||
return str.replace(/\s+/, ' ').replace(/^\s|\s$/, '');
|
||||
};
|
||||
|
||||
|
||||
// 查找子元素
|
||||
Class.fn.find = function(selector){
|
||||
var that = this;
|
||||
@ -267,7 +810,7 @@
|
||||
var isObject = typeof selector === 'object';
|
||||
|
||||
this.each(function(i, item){
|
||||
var children = isObject && item.contains(selector)
|
||||
var children = isObject && item.contains(selector)
|
||||
? selector
|
||||
: item.querySelectorAll(selector || null);
|
||||
|
||||
@ -278,24 +821,24 @@
|
||||
|
||||
return lay(elem);
|
||||
};
|
||||
|
||||
|
||||
// 元素遍历
|
||||
Class.fn.each = function(fn){
|
||||
return lay.each.call(this, this, fn);
|
||||
};
|
||||
|
||||
|
||||
// 添加 className
|
||||
Class.fn.addClass = function(className, type){
|
||||
return this.each(function(index, item){
|
||||
item.className = Class[type ? 'removeStr' : 'addStr'](item.className, className)
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 移除 className
|
||||
Class.fn.removeClass = function(className){
|
||||
return this.addClass(className, true);
|
||||
};
|
||||
|
||||
|
||||
// 是否包含 css 类
|
||||
Class.fn.hasClass = function(className){
|
||||
var has = false;
|
||||
@ -306,7 +849,7 @@
|
||||
});
|
||||
return has;
|
||||
};
|
||||
|
||||
|
||||
// 添加或获取 css style
|
||||
Class.fn.css = function(key, value){
|
||||
var that = this;
|
||||
@ -319,9 +862,9 @@
|
||||
typeof key === 'object' ? lay.each(key, function(thisKey, thisValue){
|
||||
item.style[thisKey] = parseValue(thisValue);
|
||||
}) : item.style[key] = parseValue(value);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 添加或获取宽度
|
||||
Class.fn.width = function(value){
|
||||
var that = this;
|
||||
@ -329,9 +872,9 @@
|
||||
if(that.length > 0) return that[0].offsetWidth; // 此处还需做兼容
|
||||
}() : that.each(function(index, item){
|
||||
that.css('width', value);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 添加或获取高度
|
||||
Class.fn.height = function(value){
|
||||
var that = this;
|
||||
@ -339,9 +882,9 @@
|
||||
if(that.length > 0) return that[0].offsetHeight; // 此处还需做兼容
|
||||
}() : that.each(function(index, item){
|
||||
that.css('height', value);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 添加或获取属性
|
||||
Class.fn.attr = function(key, value){
|
||||
var that = this;
|
||||
@ -349,16 +892,16 @@
|
||||
if(that.length > 0) return that[0].getAttribute(key);
|
||||
}() : that.each(function(index, item){
|
||||
item.setAttribute(key, value);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 移除属性
|
||||
Class.fn.removeAttr = function(key){
|
||||
return this.each(function(index, item){
|
||||
item.removeAttribute(key);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 设置或获取 HTML 内容
|
||||
Class.fn.html = function(html){
|
||||
var that = this;
|
||||
@ -368,7 +911,7 @@
|
||||
item.innerHTML = html;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 设置或获取值
|
||||
Class.fn.val = function(value){
|
||||
var that = this;
|
||||
@ -378,50 +921,45 @@
|
||||
item.value = value;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 追加内容
|
||||
Class.fn.append = function(elem){
|
||||
return this.each(function(index, item){
|
||||
typeof elem === 'object'
|
||||
typeof elem === 'object'
|
||||
? item.appendChild(elem)
|
||||
: item.innerHTML = item.innerHTML + elem;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 移除内容
|
||||
Class.fn.remove = function(elem){
|
||||
return this.each(function(index, item){
|
||||
elem ? item.removeChild(elem) : item.parentNode.removeChild(item);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 事件绑定
|
||||
Class.fn.on = function(eventName, fn){
|
||||
Class.fn.on = function(eventName, fn, options){
|
||||
return this.each(function(index, item){
|
||||
item.attachEvent ? item.attachEvent('on' + eventName, function(e){
|
||||
e.target = e.srcElement;
|
||||
fn.call(item, e);
|
||||
}) : item.addEventListener(eventName, fn, false);
|
||||
lay.addEvent(item, eventName, fn, options)
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 解除事件
|
||||
Class.fn.off = function(eventName, fn){
|
||||
Class.fn.off = function(eventName, fn, options){
|
||||
return this.each(function(index, item){
|
||||
item.detachEvent
|
||||
? item.detachEvent('on'+ eventName, fn)
|
||||
: item.removeEventListener(eventName, fn, false);
|
||||
lay.removeEvent(item, eventName, fn, options)
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// export
|
||||
window.lay = lay;
|
||||
|
||||
|
||||
// 输出为 layui 模块
|
||||
if(window.layui && layui.define){
|
||||
layui.define(function(exports){
|
||||
exports(MOD_NAME, lay);
|
||||
});
|
||||
}
|
||||
|
||||
}(window, window.document); // gulp build: lay-footer
|
||||
|
||||
}(window, window.document); // gulp build: lay-footer
|
||||
|
Reference in New Issue
Block a user