为何在函数内部添加overlay后无法绑定元素事件?
解决动态添加Overlay的事件绑定问题
要实现点击图片时动态创建Overlay、关闭时彻底移除,同时解决动态元素无法绑定事件的问题,核心是使用事件委托——将事件绑定到页面加载时就存在的静态元素(比如document),而非动态生成的元素本身。以下是修改后的完整代码及关键改动说明:
修改后的代码
/* Gallery Fancybox */ var gallery = $('.item-detail__gallery'), galleryImgs = gallery.find('img'), galleryImgWrappers = gallery.find('a'), image = $('<img>', {class: 'lightbox__img'}), loadingImg = $('<img>', {src: '/bazar/assets/img/icons/circle.svg', class: 'loading-img'}); // Show overlay after click on a element of gallery gallery.find('a').on('click', function(event) { event.preventDefault(); // 动态创建Overlay并添加到body var overlay = $('<div id="overlay"><div id="overlay__left-arrow-block"><span id="overlay__left-arrow"></span></div><div id="top-margin"></div><div id="overlay__img-wrapper"></div><div id="overlay__bottom-slider"></div><div id="overlay__right-arrow-block"><span id="overlay__right-arrow"></span></div><div id="overlay__close-btn">Zavrieť</div></div>'); overlay.appendTo('body'); // Define variables var galleryImgWrapperHref = $(this).attr('href'); // Show chosen image in overlay image.attr('src', galleryImgWrapperHref); // Show loading image before image is loaded loadingImg.appendTo(overlay.find('#overlay__img-wrapper')).show(); // Image will show after it will be loaded, before loading image is showed image.on('load', function() { image.appendTo(overlay.find('#overlay__img-wrapper')); loadingImg.hide(); // Hide loading image after image was loaded }); // Make images slider for thumbnails from gallery galleryImgs.each(function() { var src = $(this).attr('src'), href = $(this).parent().attr('href'), thumbWrapper = $('<a/>', {class: 'overlay__img-thumb-wrapper'}), // 替换id为class,避免重复ID问题 thumbImg = $('<img>', {class: 'lightbox__img-thumb'}); // Add thumb image src and href to a element from original element in gallery thumbWrapper.attr('href', href); thumbImg.attr('src', src); thumbWrapper.html(thumbImg); // Put image into thumbImgWrapper thumbWrapper.appendTo(overlay.find('#overlay__bottom-slider')); // If src of thumb and main image is the same then mark thumb as active if ((thumbImg.attr('src').substring(thumbImg.attr('src').lastIndexOf("/") + 1) == image.attr('src').substring(image.attr('src').lastIndexOf("/") + 1))) { thumbWrapper.addClass('img-active'); } }); }); // 事件委托:点击底部缩略图切换图片 $(document).on('click','#overlay__bottom-slider a', function(event) { event.preventDefault(); var overlay = $(this).closest('#overlay'), thumbWrapperHref = $(this).attr('href'), thumbWrapperCurrent = $(this); // Remove old active class and add on current element overlay.find('#overlay__bottom-slider').children().removeClass('img-active'); thumbWrapperCurrent.addClass('img-active'); // show loading img and hide old image loadingImg.show(); image.hide(); image.attr('src', thumbWrapperHref); // After new image will be loaded show it and hide loading image image.on('load', function() { loadingImg.hide(); image.show(); }) }); // 事件委托:点击图片容器关闭Overlay $(document).on('click', '#overlay__img-wrapper', function() { $(this).closest('#overlay').remove(); }); // 事件委托:点击关闭按钮移除Overlay $(document).on('click', '#overlay__close-btn', function() { $(this).closest('#overlay').remove(); }); // 按ESC键移除Overlay $(document).on('keyup',function(event) { if (event.which == 27) $('#overlay').remove(); }); // 事件委托:点击左箭头切换图片 $(document).on('click', '#overlay__left-arrow-block', function() { var overlay = $(this).closest('#overlay'), bottomSlider = overlay.find('#overlay__bottom-slider'), thumbWrapper = bottomSlider.find('.img-active'); let prevImageSrc, targetThumb; // Action if it is first thumbWrapper - next wrapper is last one if (thumbWrapper.is(':first-child')) { targetThumb = bottomSlider.children().last(); prevImageSrc = targetThumb.attr('href'); } else { targetThumb = thumbWrapper.prev(); prevImageSrc = targetThumb.attr('href'); } // 更新active状态 thumbWrapper.removeClass('img-active'); targetThumb.addClass('img-active'); // show loading img and hide old image loadingImg.show(); image.hide(); image.attr('src', prevImageSrc); // After new image will be loaded show it and hide loading image image.on('load', function() { loadingImg.hide(); image.show(); }); }); // 补充右箭头事件(原代码遗漏) $(document).on('click', '#overlay__right-arrow-block', function() { var overlay = $(this).closest('#overlay'), bottomSlider = overlay.find('#overlay__bottom-slider'), thumbWrapper = bottomSlider.find('.img-active'); let nextImageSrc, targetThumb; // Action if it is last thumbWrapper - next wrapper is first one if (thumbWrapper.is(':last-child')) { targetThumb = bottomSlider.children().first(); nextImageSrc = targetThumb.attr('href'); } else { targetThumb = thumbWrapper.next(); nextImageSrc = targetThumb.attr('href'); } // 更新active状态 thumbWrapper.removeClass('img-active'); targetThumb.addClass('img-active'); // show loading img and hide old image loadingImg.show(); image.hide(); image.attr('src', nextImageSrc); // After new image will be loaded show it and hide loading image image.on('load', function() { loadingImg.hide(); image.show(); }); });
关键改动说明
- 动态创建Overlay:将Overlay的创建逻辑移到图片点击事件内部,每次点击生成全新的Overlay实例,避免复用旧元素导致的状态混乱。
- 事件委托绑定:所有针对Overlay内部元素的事件(关闭按钮、左右箭头、缩略图等),都通过
$(document).on()绑定到document,确保动态生成的元素能触发事件。 - 彻底移除Overlay:所有关闭操作(点击关闭按钮、图片容器、ESC键)都使用
remove()而非hide(),彻底从DOM中移除元素,释放资源。 - 修复重复ID问题:将缩略图容器的
id="overlay__img-thumb-wrapper"改为class="overlay__img-thumb-wrapper",避免多次创建Overlay时出现重复ID的DOM问题。 - 补充右箭头事件:原代码中遗漏了右箭头的点击逻辑,补上完整的切换功能。
内容的提问来源于stack exchange,提问作者Dump
相关产品推荐
相关产品推荐

