From a1e084c6b4ff4a561394793c54d929ec40b0a99b Mon Sep 17 00:00:00 2001 From: morning-star <26325820+Sight-wcg@users.noreply.github.com> Date: Thu, 17 Apr 2025 23:11:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(form-select):=20select=20=E7=82=B9?= =?UTF-8?q?=E5=87=BB=E5=A4=96=E9=83=A8=E5=85=B3=E9=97=AD=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=20iframe=20(#2631)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(lay): lay.onClickoutside 新增 detectIframe 选项 * feat(form-select): select 支持检测 iframe 点击 * feat(lay): lay.touchSwipe 新增 preventDefault 选项 * docs: 优化部分注释文案,避免非技术人员理解错位 尽量避免词汇:监听、侦听。可用事件「触发」或「响应」等相近含义的词语替代 --------- Co-authored-by: 贤心 <3277200+sentsim@users.noreply.github.com> --- src/modules/form.js | 7 ++++-- src/modules/lay.js | 55 ++++++++++++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/modules/form.js b/src/modules/form.js index 3de4b6cc..abbb71a3 100644 --- a/src/modules/form.js +++ b/src/modules/form.js @@ -554,7 +554,7 @@ layui.define(['lay', 'layer', 'util'], function(exports){ hideDown(); initValue && input.val(initValue); }, - {ignore: title} + {ignore: title, detectIframe: true, capture: false} ); }; @@ -563,7 +563,10 @@ layui.define(['lay', 'layer', 'util'], function(exports){ title.parent().removeClass(CLASS+'ed ' + CLASS+'up'); input.blur(); isCreatable && dl.children('.' + CREATE_OPTION).remove(); - removeClickOutsideEvent && removeClickOutsideEvent(); + if(typeof removeClickOutsideEvent === 'function'){ + removeClickOutsideEvent(); + removeClickOutsideEvent = null; + } if(isAppendTo){ reElem.detach(); $(window).off('resize.lay_select_resize'); diff --git a/src/modules/lay.js b/src/modules/lay.js index af5f37d3..d19abc0e 100644 --- a/src/modules/lay.js +++ b/src/modules/lay.js @@ -551,11 +551,12 @@ /** * 基于 touch 事件的触摸滑动 * @param {string | HTMLElement | JQuery} elem - HTML 元素 - * @param {{onTouchStart?: touchSwipeCallback, onTouchMove?: touchSwipeCallback, onTouchEnd?: touchSwipeCallback}} opts - 配置项 + * @param {{onTouchStart?: touchSwipeCallback; onTouchMove?: touchSwipeCallback; onTouchEnd?: touchSwipeCallback; preventDefault?: boolean}} opts - 配置项 */ lay.touchSwipe = function(elem, opts){ var options = opts var targetElem = lay(elem)[0]; + var preventDefault = 'preventDefault' in options ? options.preventDefault : true; if(!targetElem || !lay.touchEventsSupported()) return; @@ -582,7 +583,9 @@ } var onMove = function(e){ - e.preventDefault(); + if(preventDefault){ + e.preventDefault(); + } state.pointerEnd.x = e.touches[0].clientX; state.pointerEnd.y = e.touches[0].clientY; state.distanceX = state.pointerStart.x - state.pointerEnd.x; @@ -680,15 +683,16 @@ }(); /** - * 监听指定元素外部的点击 - * @param {HTMLElement} target - 被监听的元素 + * 绑定指定元素外部的点击事件 + * @param {HTMLElement} target - 响应事件的元素 * @param {(e: Event) => void} handler - 事件触发时执行的函数 * @param {object} [options] - 选项 - * @param {string} [options.event="pointerdown"] - 监听的事件类型 - * @param {HTMLElement | Window} [options.scope=document] - 监听范围 - * @param {Array} [options.ignore] - 忽略监听的元素或选择器字符串 - * @param {boolean} [options.capture=true] - 对内部事件侦听器使用捕获阶段 - * @returns {() => void} - 返回一个停止事件监听的函数 + * @param {string} [options.event="pointerdown"] - 事件类型 + * @param {HTMLElement | Window} [options.scope=document] - 事件范围 + * @param {Array} [options.ignore] - 忽略触发事件的元素或选择器字符串 + * @param {boolean} [options.capture=true] - 对内部事件 listener 使用捕获阶段 + * @param {boolean} [options.detectIframe] - 是否检测 iframe + * @returns {() => void} - 返回一个停止事件响应的函数 */ lay.onClickOutside = function(target, handler, options){ options = options || {}; @@ -696,6 +700,7 @@ var scopeTarget = options.scope || document; var ignore = options.ignore || []; var useCapture = 'capture' in options ? options.capture : true; + var detectIframe = options.detectIframe; var listener = function(event){ var el = target; @@ -764,13 +769,31 @@ } } - return bindEventListener( - scopeTarget, - eventType, - listener, - lay.passiveSupported ? { passive: true, capture: useCapture } : useCapture - ); - } + var cleanup = [ + bindEventListener( + scopeTarget, + eventType, + listener, + lay.passiveSupported ? { passive: true, capture: useCapture } : useCapture + ), + detectIframe && bindEventListener(window, 'blur', function(event){ + setTimeout(function(){ + if(document.activeElement && document.activeElement.tagName === 'IFRAME' + && target.contains && !target.contains(document.activeElement) + ){ + handler(event); + } + }, 0); + }) + ]; + + return function(){ + for(var i=0; i < cleanup.length; i++){ + cleanup[i] && cleanup[i](); + } + cleanup = null; + } + }; var hasOwnProperty = Object.prototype.hasOwnProperty; lay.hasOwn = function(obj, prop){