Показ контента любой страницы сайта во всплывающем окне (быстрый просмотр)

Просмотров: 184

Задача: при клике на кнопку показывать попап-окно или выдвигающуюся панель с загрузкой в неё нужной страницы сайта и вырезанием контента заданного блока.

Для реализации подобного функционала в 1С-Битрикс есть Javascript-расширение sidepanel модуля UI. Подробнее рассмотрено в заметке Показ страницы сайта в слайдере.

Однако это расширение достаточно тяжёлое. При подключении оно тянет за собой большие js/css-файлы и подгружает все начертания шрифта OpenSans. Чтобы избежать чрезмерной нагрузки, сделал аналогичный компонент.

Кроме того, с помощью стилей можно привести окно к любому виду и использовать любые анимации: выезд сбоку/снизу, появление в центре и т.д.

Можно скачать готовый компонент. У него две настройки: "URL страницы" для загрузки и "Селектор" — содержимое которого нужно показать в окне (остальной контент страницы будет обрезан).

Скриншот настроек компонента Битрикс

Компонент выведет кнопку. Далее, с помощью редактирования template.php, стилей и скрипта, можно подогнать поведение окна. Пример работы:

Основной скрипт быстрого просмотра

Ниже приведена основа компонента — js-скрипт, который выполняет основную работу. А template.php и стили максимально простые. Проблем возникнуть не должно.

document.addEventListener('DOMContentLoaded', function() {
    // Получаем все элементы-кнопки, которые открывают боковую панель
    const openBtns = document.querySelectorAll('.open-panel-btn');
    // Получаем кнопку закрытия панели
    const closeBtn = document.getElementById('closeSidePanel');
    // Получаем саму панель
    const panel = document.getElementById('sidePanel');
    // Получаем оверлей (затемнение фона)
    const overlay = document.getElementById('sidePanelOverlay');
    // Получаем контейнер для контента внутри панели
    const content = document.getElementById('sidePanelContent');

    // Для каждой кнопки открытия панели добавляем обработчик клика
    openBtns.forEach(btn => {
        btn.addEventListener('click', function() {
            // Получаем URL страницы, которую нужно загрузить в панель
            const pageUrl = this.getAttribute('data-page-url');
            // Получаем селектор блока, который нужно взять из загружаемой страницы (по умолчанию тег body)
            const blockSelector = this.getAttribute('data-block-selector') || 'body';

            // Если URL указан, загружаем контент и открываем панель
            if (pageUrl) {
                loadContent(pageUrl, blockSelector);
                openPanel();
            }
        });
    });

    // Добавляем обработчик клика для кнопки закрытия панели
    closeBtn.addEventListener('click', closePanel);
    // Добавляем обработчик клика для оверлея (закрытие при клике вне панели)
    overlay.addEventListener('click', closePanel);

    // Добавляем обработчик нажатия клавиши Escape для закрытия панели
    document.addEventListener('keydown', function(e) {
        if (e.key === 'Escape' && panel.classList.contains('active')) {
            closePanel();
        }
    });

    // Функция открытия панели: добавляет классы активности и блокирует прокрутку body
    function openPanel() {
        panel.classList.add('active');
        overlay.classList.add('active');
        document.body.style.overflow = 'hidden';
    }

    // Функция закрытия панели: убирает классы активности и возвращает прокрутку body
    function closePanel() {
        panel.classList.remove('active');
        overlay.classList.remove('active');
        document.body.style.overflow = '';
    }

    // Функция загрузки контента по URL и вставки нужного блока в панель
    function loadContent(url, selector) {
        content.innerHTML = 'Загрузка...';
        fetch(url)
            .then(response => {
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                return response.text();
            })
            .then(html => {
                const tempDiv = document.createElement('div');
                tempDiv.innerHTML = html;

                // --- Стили ---
                const links = tempDiv.querySelectorAll('link[rel="stylesheet"]');
                links.forEach(link => {
                    if (!Array.from(document.head.querySelectorAll('link[rel="stylesheet"]')).some(l => l.href === link.href)) {
                        const newLink = document.createElement('link');
                        for (let attr of link.attributes) {
                            newLink.setAttribute(attr.name, attr.value);
                        }
                        document.head.appendChild(newLink);
                    }
                });
                const styles = tempDiv.querySelectorAll('style');
                styles.forEach(style => {
                    if (!Array.from(document.head.querySelectorAll('style')).some(s => s.textContent === style.textContent)) {
                        const newStyle = document.createElement('style');
                        newStyle.textContent = style.textContent;
                        document.head.appendChild(newStyle);
                    }
                });

                // --- Контент ---
                const targetBlock = tempDiv.querySelector(selector);
                if (targetBlock) {
                    content.innerHTML = targetBlock.innerHTML;
                } else {
                    content.innerHTML = 'Блок не найден на странице';
                }

                // --- Скрипты ---
                // Собираем все скрипты из загруженной страницы
                const allScripts = tempDiv.querySelectorAll('script');
                allScripts.forEach(script => {
                    const newScript = document.createElement('script');
                    for (let attr of script.attributes) {
                        newScript.setAttribute(attr.name, attr.value);
                    }
                    if (script.src) {
                        // Проверяем, есть ли такой src уже в head/body
                        if (!Array.from(document.querySelectorAll('script[src]')).some(s => s.src === script.src)) {
                            newScript.src = script.src;
                            // Если defer/async/type — переносим атрибуты
                            if (script.defer) newScript.defer = true;
                            if (script.async) newScript.async = true;
                            if (script.type) newScript.type = script.type;
                            document.head.appendChild(newScript);
                        }
                    } else {
                        newScript.textContent = script.textContent;
                        if (script.type) newScript.type = script.type;
                        document.body.appendChild(newScript);
                    }
                });
            })
            .catch(error => {
                content.innerHTML = 'Ошибка загрузки контента';
                console.error('Error loading content:', error);
            });
    }
});
// Конец скрипта боковой панели

В принципе, можете использовать наработки компонента для чего угодно, например для реализации функционала показа быстрого просмотра товаров или для отображения формы обратной связи, онлайн-калькулятора, информации о доставке, контактных данных и других вспомогательных окон.

Показ быстрого просмотра товара

Стоимость разработки на 1С-Битрикс:

Индивидуальная разработка магазина

от 500 000 руб. от 5-ти недель

Разработка магазина на 1С-Битрикс с нуля. Дизайн, сборка и оптимизация производительности под конкретный проект и требования. Реализация любого функционала без ограничений готовых решений.

Запуск сайта на готовом решении

от 100 000 руб. от 7-ми дней

Вариант для тех, кто не хочет тратить много средств на индивидуальный проект, и не имеет серьезных требований к сайту. Магазин, быстро запускается на базе одного из 200-та готовых решений.

Мобильное приложение

от 500 000 руб. от 1-го месяца

Разработка кроссплатформенного мобильного приложения, которое не уступает нативным решениям как в производительности, так и пользовательском опыте. Публикуется в AppStore, GooglePlay и RuStore

Сайт компании

от 350 000 руб. от 1-го месяца

Корпоративный сайт с информационными разделами, каталогом товаров или услуг. Включает формы обратной связи карточек каталога, любое количество статичных и динамичных разделов.

Инфресурс

от 400 000 руб. от 5-ти недель

Информационный ресурс любой сложности. Сайт для СМИ, городской портал или многопользовательская доска объявлений. Внутренние форумы, блоги- по необходимости.

Лечение сайтов от вирусов

от 40 000 руб. от 2-х дней

Выполню полную проверку сайта и окружения. В случае обнаружения вирусов проведу полный комплекс лечения проекта и закрытия лазеек.