diff --git a/src/modules/dropdown.js b/src/modules/dropdown.js index 41caf7e2..ef558f55 100644 --- a/src/modules/dropdown.js +++ b/src/modules/dropdown.js @@ -9,6 +9,7 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) { var $ = layui.$; var laytpl = layui.laytpl; var util = layui.util; + var lay = layui.lay; var hint = layui.hint(); var i18n = layui.i18n; var device = layui.device(); @@ -20,6 +21,8 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) { var MOD_INDEX_OPENED = MOD_INDEX + '_opened'; var MOD_ID = 'lay-' + MOD_NAME + '-id'; + var resizeObserver = lay._createResizeObserver(MOD_NAME); + // 外部接口 var dropdown = { config: { @@ -361,6 +364,11 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) { } }); + if(resizeObserver){ + resizeObserver.observe(options.elem[0], that.position.bind(that)); + resizeObserver.observe(mainElem[0], that.position.bind(that)); + } + // 组件打开完毕的事件 typeof options.ready === 'function' && options.ready(mainElem, options.elem); }; @@ -392,6 +400,10 @@ layui.define(['i18n', 'jquery', 'laytpl', 'lay', 'util'], function(exports) { mainElem.prev('.' + STR_ELEM_SHADE).remove(); // 先移除遮罩 mainElem.remove(); options.elem.removeData(MOD_INDEX_OPENED); + if(resizeObserver){ + resizeObserver.unobserve(options.elem[0]); + resizeObserver.unobserve(mainElem[0]); + } delete dropdown.thisId; typeof options.close === 'function' && options.close(options.elem); } diff --git a/src/modules/form.js b/src/modules/form.js index 8b97692d..8ec8f02b 100644 --- a/src/modules/form.js +++ b/src/modules/form.js @@ -8,6 +8,7 @@ layui.define(['lay', 'i18n', 'layer', 'util'], function(exports){ var $ = layui.$; var layer = layui.layer; var util = layui.util; + var lay = layui.lay; var hint = layui.hint(); var device = layui.device(); var i18n = layui.i18n; @@ -21,6 +22,8 @@ layui.define(['lay', 'i18n', 'layer', 'util'], function(exports){ var OUT_OF_RANGE = 'layui-input-number-out-of-range'; var BAD_INPUT = 'layui-input-number-invalid'; + var resizeObserver = lay._createResizeObserver(MOD_NAME); + // ie8 中可以获取到 input 元素的 'indeterminate' 属性描述符,但重新定义 getter/setter 无效,无报错 // AppleWebKit/537.36 无法获取 input 元素任意属性的属性描述符(包括lookupGetter),但可以重新定义 getter/setter var needCheckboxFallback = (lay.ie && parseFloat(lay.ie) === 8) @@ -523,6 +526,9 @@ layui.define(['lay', 'i18n', 'layer', 'util'], function(exports){ updatePosition(); $(window).on('resize.lay_select_resize', updatePosition); + if(resizeObserver){ + resizeObserver.observe(reElem[0], updatePosition); + } } var top = reElem.offset().top + reElem.outerHeight() + 5 - $win.scrollTop(); var dlHeight = dl.outerHeight(); @@ -575,6 +581,9 @@ layui.define(['lay', 'i18n', 'layer', 'util'], function(exports){ if(isAppendTo){ reElem.detach(); $(window).off('resize.lay_select_resize'); + if(resizeObserver){ + resizeObserver.unobserve(reElem[0]); + } } if(choose) return; diff --git a/src/modules/lay.js b/src/modules/lay.js index 8a95f278..86c5a4b0 100644 --- a/src/modules/lay.js +++ b/src/modules/lay.js @@ -836,6 +836,103 @@ .replace(/\&/g, '&'); }; + /** + * 生成唯一的 ID 字符串 + * @param {string} prefix ID前缀,默认为'id' + * @returns {string} 唯一ID字符串 + */ + var generateUniqueId = (function () { + var counter = 0; + var lastTimestamp = null; + + return function (prefix) { + prefix = prefix || 'id'; + var timestamp = new Date().getTime(); + + // 如果时间戳与上一次相同,增加计数器 + // 否则重置计数器 + if (timestamp === lastTimestamp) { + counter++; + } else { + counter = 0; + lastTimestamp = timestamp; + } + + // 结合时间戳、随机数和计数器生成ID + var random = Math.floor(Math.random() * 10000); + + return prefix + '-' + timestamp + '-' + random + '-' + counter; + }; + })(); + + /** + * 创建全局 ResizeObserver 实例 + * @param {string} namespace 命名空间,用于区分不同的 ResizeObserver 实例 + * @returns {ResizeObserver | null} 全局 ResizeObserver 实例或 null(如果不支持) + */ + lay._createResizeObserver = function (namespace) { + if (typeof window.ResizeObserver === 'undefined') { + console.log && console.log('ResizeObserver is not supported in this browser'); + return null; + } + + var ATTR_NAME = 'lay-resizeobserver-key'; + var handlerCache = {}; + + var o = new ResizeObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var attrValue = entries[i].target.getAttribute(ATTR_NAME); + + if (attrValue) { + var callback = handlerCache[attrValue]; + if (typeof callback === 'function') { + callback(entries[i]); + } + } + } + }); + + return Object.freeze({ + observe: function (element, callback) { + if (!element || !(element instanceof Element)) { + console.log && console.log('createResizeObserver: Cannot observe non-Element.'); + return; + } + + var attrValue = element.getAttribute(ATTR_NAME); + if (!attrValue) { + attrValue = generateUniqueId(namespace); + element.setAttribute(ATTR_NAME, attrValue); + } + + handlerCache[attrValue] = callback; + o.observe(element); + }, + unobserve: function (element) { + if (!element || !(element instanceof Element)) { + console.log && console.log('createResizeObserver: Cannot unobserve non-Element.'); + return; + } + + var attrValue = element.getAttribute(ATTR_NAME); + if (!attrValue) { + return; + } + + // 清除相关回调 + if (handlerCache[attrValue]) { + delete handlerCache[attrValue]; + } + + o.unobserve(element); + }, + disconnect: function () { + o.disconnect(); + handlerCache = {}; + } + }); + }; + /* * lay 元素操作