Сейчас узнаем, какой подарок выпадет именно Вам
Крутите колесо
Как добавить эффект лупы для фото в Tilda

Как добавить эффект лупы для фото в Tilda

1
Добавили на страницу блок с картинками и задали ему класс uc-lens-mode
2
Если для картинки не нужен эффект, то задаём ей атрибут data-lens = no
3
Добавили код на страницу в блок Т123
Mo-ti Level Up
Видео инструкции по добавлению кода и работе с Zero Block.
Добавляем эффект приближения лупы при наведении на фотографии
Фрагмент видео
Библиотека для примера
<script>
document.addEventListener('DOMContentLoaded', function() {
    
    var lensSize = 200; //размер лупы
    var zoomLevel = 2.0; //увеличение
    var touchOn = true; // true — лупа на мобильных включена, false — отключена
    var longPressDelay = 100; // миллисекунды для долгого нажатия
    
    var isTouchDevice = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
    
    function hasLensNo(el) {
        var current = el;
        while (current && current !== document.body) {
            if (current.getAttribute('data-lens') === 'no') {
                return true;
            }
            current = current.parentElement;
        }
        return false;
    }

    function getImageUrl(element) {
    
        var url = element.getAttribute('data-original');
        if (url) return url;
        
        
        if (element.tagName === 'IMG') {
            url = element.getAttribute('src');
            if (url) return url;
        }
        
        
        var style = element.getAttribute('style') || '';
        var match = style.match(/background-image\s*:\s*url\(['"]?([^'"()]+)['"]?\)/i);
        if (match && match[1]) {
            return match[1];
        }

        var computedStyle = window.getComputedStyle(element);
        var bgImage = computedStyle.getPropertyValue('background-image');
        if (bgImage && bgImage !== 'none') {
            match = bgImage.match(/url\(['"]?([^'"()]+)['"]?\)/i);
            if (match && match[1]) {
                return match[1];
            }
        }
        
        return null;
    }
    

    var sliderLensInstances = {};
    
    function getSliderLens(sliderWrapper) {
        var sliderId = sliderWrapper.closest('.t-rec')?.id || 'default';
        if (!sliderLensInstances[sliderId]) {
            var lens = document.createElement('div');
            lens.className = 't-zoom-lens';
            lens.style.cssText = `
                position: fixed;
                width: ${lensSize}px;
                height: ${lensSize}px;
                border-radius: 50%;
                border: 3px solid rgba(255,255,255,0.8);
                box-shadow: 0 4px 20px rgba(0,0,0,0.3), inset 0 0 10px rgba(0,0,0,0.1);
                pointer-events: none;
                opacity: 0;
                transition: opacity 0.2s ease;
                overflow: hidden;
                z-index: 9999;
                background-repeat: no-repeat;
                background-color: #fff;
                display: none;
            `;
            document.body.appendChild(lens);
            sliderLensInstances[sliderId] = lens;
        }
        return sliderLensInstances[sliderId];
    }
    
    function updateSliderLens(lens, e, bgImg) {
        var rect = bgImg.getBoundingClientRect();
        var x = e.clientX;
        var y = e.clientY;
        
        if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom) {
            lens.style.opacity = '0';
            lens.style.display = 'none';
            return;
        }
        
        lens.style.display = 'block';
        lens.style.opacity = '1';
        
        var lensX = x - lensSize / 2;
        var lensY = y - lensSize / 2;
        
        lensX = Math.max(0, Math.min(lensX, window.innerWidth - lensSize));
        lensY = Math.max(0, Math.min(lensY, window.innerHeight - lensSize));
        
        lens.style.left = lensX + 'px';
        lens.style.top = lensY + 'px';
        
        var localX = x - rect.left;
        var localY = y - rect.top;
        
        var bgX = (localX / rect.width) * 100;
        var bgY = (localY / rect.height) * 100;
        
        lens.style.backgroundSize = (rect.width * zoomLevel) + 'px ' + (rect.height * zoomLevel) + 'px';
        lens.style.backgroundPosition = bgX + '% ' + bgY + '%';
    }
    
    function initSlider(sliderWrapper) {
        var wrapper = sliderWrapper.querySelector('.t-slds__items-wrapper');
        if (!wrapper) return;
        if (wrapper._lensInitialized) return;
        wrapper._lensInitialized = true;
        
        var lens = getSliderLens(sliderWrapper);
        var currentBgImg = null;
        var currentZoomUrl = null;
        
        function getActiveSlide() {
            return wrapper.querySelector('.t-slds__item.t-slds__item_active');
        }
        
        function updateActiveSlide() {
            var activeSlide = getActiveSlide();
            if (!activeSlide) return;
            
            var bgImg = activeSlide.querySelector('.t-slds__bgimg.t-bgimg, .t-bgimg');
            if (!bgImg) return;
            
            var zoomUrl = getImageUrl(bgImg);
            if (!zoomUrl) return;
            
            if (currentZoomUrl !== zoomUrl) {
                currentZoomUrl = zoomUrl;
                lens.style.backgroundImage = 'url(' + zoomUrl + ')';
            }
            
            currentBgImg = bgImg;
        }
        
        var slideObserver = new MutationObserver(function() {
            updateActiveSlide();
        });
        
        var allSlides = wrapper.querySelectorAll('.t-slds__item');
        allSlides.forEach(function(slide) {
            slideObserver.observe(slide, { attributes: true, attributeFilter: ['class'] });
        });
        
        setTimeout(updateActiveSlide, 100);
        
        function onMouseEnter(e) {
            if (!currentBgImg) {
                updateActiveSlide();
                if (!currentBgImg) return;
            }
            if (currentZoomUrl) {
                lens.style.backgroundImage = 'url(' + currentZoomUrl + ')';
            }
        }
        
        function onMouseMove(e) {
            if (!currentBgImg) {
                updateActiveSlide();
                if (!currentBgImg) return;
            }
            updateSliderLens(lens, e, currentBgImg);
        }
        
        function onMouseLeave(e) {
            lens.style.opacity = '0';
            lens.style.display = 'none';
        }
        
        wrapper.addEventListener('mouseenter', onMouseEnter);
        wrapper.addEventListener('mousemove', onMouseMove);
        wrapper.addEventListener('mouseleave', onMouseLeave);
        
        if (isTouchDevice && touchOn) {
            var longPressTimer = null;
            var isLongPress = false;
            var startX = 0, startY = 0;
            var moveThreshold = 10;
            
            wrapper.addEventListener('touchstart', function(e) {
                var touch = e.touches[0];
                startX = touch.clientX;
                startY = touch.clientY;
                isLongPress = false;
                
                if (!currentBgImg) {
                    updateActiveSlide();
                    if (!currentBgImg) return;
                }
                
                longPressTimer = setTimeout(function() {
                    isLongPress = true;
                    if (currentZoomUrl) {
                        lens.style.backgroundImage = 'url(' + currentZoomUrl + ')';
                    }
                    updateSliderLens(lens, touch, currentBgImg);
                }, longPressDelay);
            }, { passive: true });
            
            wrapper.addEventListener('touchmove', function(e) {
                var touch = e.touches[0];
                
                if (isLongPress) {
                    e.preventDefault();
                    if (currentBgImg) {
                        updateSliderLens(lens, touch, currentBgImg);
                    }
                    return;
                }
                
                var dx = Math.abs(touch.clientX - startX);
                var dy = Math.abs(touch.clientY - startY);
                if (dx > moveThreshold || dy > moveThreshold) {
                    clearTimeout(longPressTimer);
                    longPressTimer = null;
                }
            }, { passive: true });
            
            wrapper.addEventListener('touchend', function(e) {
                clearTimeout(longPressTimer);
                longPressTimer = null;
                lens.style.opacity = '0';
                lens.style.display = 'none';
                isLongPress = false;
            });
            
            wrapper.addEventListener('touchcancel', function(e) {
                clearTimeout(longPressTimer);
                longPressTimer = null;
                lens.style.opacity = '0';
                lens.style.display = 'none';
                isLongPress = false;
            });
        }
    }
    
  
    function createLocalLens(container, zoomUrl, targetForCoords) {
        if (!zoomUrl) return;
        if (hasLensNo(container)) return;
        if (container.querySelector('.t-zoom-lens')) return;
        
        var lens = document.createElement('div');
        lens.className = 't-zoom-lens';
        lens.style.cssText = `
            position: absolute;
            width: ${lensSize}px;
            height: ${lensSize}px;
            border-radius: 50%;
            border: 3px solid rgba(255,255,255,0.8);
            box-shadow: 0 4px 20px rgba(0,0,0,0.3), inset 0 0 10px rgba(0,0,0,0.1);
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.2s ease;
            overflow: hidden;
            z-index: 100;
            background-repeat: no-repeat;
            background-color: #fff;
        `;
        
        var coordEl = targetForCoords || container;
        
        var style = getComputedStyle(container);
        if (style.position === 'static') {
            container.style.position = 'relative';
        }
        container.appendChild(lens);
        
        function updateLocalLens(x, y) {
            var rect = coordEl.getBoundingClientRect();
            
            if (x < rect.left || x > rect.right || y < rect.top || y > rect.bottom) {
                lens.style.opacity = '0';
                return;
            }
            
            var localX = x - rect.left;
            var localY = y - rect.top;
            
            var lensX = localX - lensSize / 2;
            var lensY = localY - lensSize / 2;
            
            lensX = Math.max(0, Math.min(lensX, rect.width - lensSize));
            lensY = Math.max(0, Math.min(lensY, rect.height - lensSize));
            
            lens.style.left = lensX + 'px';
            lens.style.top = lensY + 'px';
            
            var bgX = (localX / rect.width) * 100;
            var bgY = (localY / rect.height) * 100;
            
            lens.style.backgroundSize = (rect.width * zoomLevel) + 'px ' + (rect.height * zoomLevel) + 'px';
            lens.style.backgroundPosition = bgX + '% ' + bgY + '%';
        }
        
        container.addEventListener('mouseenter', function() {
            lens.style.opacity = '1';
            lens.style.backgroundImage = 'url(' + zoomUrl + ')';
        });
        
        container.addEventListener('mouseleave', function() {
            lens.style.opacity = '0';
        });
        
        container.addEventListener('mousemove', function(e) {
            lens.style.opacity = '1';
            lens.style.backgroundImage = 'url(' + zoomUrl + ')';
            updateLocalLens(e.clientX, e.clientY);
        });
        
        if (isTouchDevice && touchOn) {
            var longPressTimer = null;
            var isLongPress = false;
            var startX = 0;
            var startY = 0;
            var moveThreshold = 10;
            
            container.addEventListener('touchstart', function(e) {
                var touch = e.touches[0];
                startX = touch.clientX;
                startY = touch.clientY;
                isLongPress = false;
                
                longPressTimer = setTimeout(function() {
                    isLongPress = true;
                    lens.style.opacity = '1';
                    lens.style.backgroundImage = 'url(' + zoomUrl + ')';
                    updateLocalLens(touch.clientX, touch.clientY);
                }, longPressDelay);
            }, { passive: true });
            
            container.addEventListener('touchmove', function(e) {
                var touch = e.touches[0];
                
                if (isLongPress) {
                    e.preventDefault();
                    updateLocalLens(touch.clientX, touch.clientY);
                    return;
                }
                
                var dx = Math.abs(touch.clientX - startX);
                var dy = Math.abs(touch.clientY - startY);
                if (dx > moveThreshold || dy > moveThreshold) {
                    clearTimeout(longPressTimer);
                    longPressTimer = null;
                }
            }, { passive: true });
            
            container.addEventListener('touchend', function(e) {
                clearTimeout(longPressTimer);
                longPressTimer = null;
                lens.style.opacity = '0';
                isLongPress = false;
            });
            
            container.addEventListener('touchcancel', function(e) {
                clearTimeout(longPressTimer);
                longPressTimer = null;
                lens.style.opacity = '0';
                isLongPress = false;
            });
        }
    }
    
  
    var lensContainers = document.querySelectorAll('.uc-lens-mode');
    if (lensContainers.length === 0) return;
    
    
    function initAllSliders() {
        lensContainers.forEach(function(container) {
            var sliders = container.querySelectorAll('.t-slds');
            sliders.forEach(function(slider) {
                initSlider(slider);
            });
        });
    }
    
    initAllSliders();
    
    var initAttempts = 0;
    var maxAttempts = 20;
    var initInterval = setInterval(function() {
        initAttempts++;
        initAllSliders();
        if (initAttempts >= maxAttempts) {
            clearInterval(initInterval);
        }
    }, 500);
    
   
    function initAllImages() {
        lensContainers.forEach(function(container) {
           
            var selectors = [
                'div.t-bgimg',
                'img.t-img',
                '.tn-atom__img',
                '.tn-atom[role="img"]'
            ];
            
            var elements = container.querySelectorAll(selectors.join(','));
            elements.forEach(function(element) {
             
                if (element.closest('.t-slds')) return;
                if (element.closest('.t-zoom-lens')) return;
                if (element._lensProcessed) return;
                
                
                element._lensProcessed = true;
 
                var zoomUrl = getImageUrl(element);
                if (!zoomUrl) return;
                
              
                var containerEl = element;
                if (element.tagName === 'IMG') {
                    var wrapper = element.parentElement;
                    
                  
                    if (wrapper.tagName === 'A' || getComputedStyle(wrapper).display === 'inline') {
                        var newWrapper = document.createElement('div');
                        newWrapper.style.cssText = 'display:inline-block; position:relative; overflow:hidden;';
                        element.parentNode.insertBefore(newWrapper, element);
                        newWrapper.appendChild(element);
                        wrapper = newWrapper;
                    }
                    
                    wrapper.style.display = 'inline-block';
                    wrapper.style.position = 'relative';
                    wrapper.style.overflow = 'hidden';
                    containerEl = wrapper;
                }
                
                createLocalLens(containerEl, zoomUrl, element);
            });
        });
    }
    
   
    setTimeout(function() {
        initAllImages();
    }, 500);
    
   
    lensContainers.forEach(function(container) {
        var imageObserver = new MutationObserver(function() {
            initAllImages();
        });
        imageObserver.observe(container, { 
            childList: true, 
            subtree: true,
            attributes: true,
            attributeFilter: ['style', 'class']
        });
    });
    
});
</script>
Made on
Tilda