Перейти к содержанию

Динамическая подмена контента на JavaScript для B2B-сайта

ПO для чпу
1 1 84 1
  • Динамическая подмена контента - это когда JavaScript меняет HTML на странице в реальном времени, не требуя перезагрузки. Для B2B-сайтов завода это критично: посетитель из поиска по Fanuc видит одно, из Heidenhain - другое, из контекста Яндекса - третье. Конверсия растёт не потому, что вы красивее соседей, а потому, что точнее отвечаете на запрос.

    Когда человек переходит по ссылке с UTM-меткой или из определённого источника, скрипт сразу подменяет заголовок, картинку, текст кнопки, даже номер телефона. Никаких конструкторов, никаких платных сервисов - просто код, который лежит в вашем репозитории и работает на всех браузерах.

    Почему JavaScript, а не GTM

    Google Tag Manager - это удобно для маркетологов, но есть подвох. GTM добавляет задержку загрузки, работает через асинхронный скрипт, и иногда контент мелькает на странице перед подменой. Пользователь видит оригинальный заголовок, потом он меняется - это смотрится неловко и влияет на восприятие.

    Прямой JavaScript, загруженный в head или в начале body, работает до того, как страница отрендерится. Контент уже изначально подменён - никаких миганий, никаких задержек. Плюс вы полностью контролируете логику: условия, переменные, обработку ошибок. Не привязаны к интерфейсу GTM и его ограничениям.

    Дополнительный бонус - это работает даже если GTM отключится или заблокируется расширением в браузере. Критично для B2B, где много IT-шников с uBlock Origin.

    • GTM: удобен для разовых тестов, но медленнее и зависит от третьей стороны
    • JavaScript: полный контроль, быстрее, работает всегда
    • Комбо: можно использовать оба параллельно для разных целей

    Готовый скрипт: парсим UTM и меняем контент

    Вот базовая структура, которая работает на любом сайте. Скрипт парсит URL, ищет нужный параметр и подменяет элементы на странице.

    const contentConfig = {
      'fanuc': {
        title: 'Оригинальные запчасти Fanuc для ЧПУ-станков',
        subtitle: 'Ремонт контроллеров 0i, 31i, iNC в 24ч',
        img: '/img/fanuc-parts.jpg',
        buttonText: 'Заказать запчасть Fanuc',
        phone: '+7 (495) 123-45-67'
      },
      'heidenhain': {
        title: 'Запчасти Heidenhain: энкодеры, платы, сервоприводы',
        subtitle: 'Гарантия 2 года на оригинал',
        img: '/img/heidenhain.jpg',
        buttonText: 'Диагностика Heidenhain',
        phone: '+7 (495) 765-43-21'
      },
      'siemens': {
        title: 'Компоненты Siemens: контроллеры и приводы',
        subtitle: 'Поддержка всех поколений S7',
        img: '/img/siemens.jpg',
        buttonText: 'Запросить предложение Siemens',
        phone: '+7 (495) 555-55-55'
      }
    };
    
    function parseUrlParam(param) {
      const urlParams = new URLSearchParams(window.location.search);
      return urlParams.get(param) ? urlParams.get(param).toLowerCase() : null;
    }
    
    function applyDynamicContent() {
      // Ищем utm_source, utm_term или utm_keyword - используй в зависимости от логики кампании
      const key = parseUrlParam('utm_source') || parseUrlParam('utm_term') || parseUrlParam('utm_keyword');
      
      if (key && contentConfig[key]) {
        const data = contentConfig[key];
        
        // Подменяем заголовок
        const titleElement = document.querySelector('.hero h1');
        if (titleElement) titleElement.textContent = data.title;
        
        // Подменяем подзаголовок
        const subtitleElement = document.querySelector('.hero p');
        if (subtitleElement) subtitleElement.textContent = data.subtitle;
        
        // Подменяем изображение
        const imgElement = document.querySelector('.hero img');
        if (imgElement) imgElement.src = data.img;
        
        // Подменяем текст кнопки
        const buttonElement = document.querySelector('.lead-form button');
        if (buttonElement) buttonElement.textContent = data.buttonText;
        
        // Подменяем номер телефона везде на странице
        const phones = document.querySelectorAll('[data-phone]');
        phones.forEach(el => {
          el.textContent = data.phone;
        });
      }
    }
    
    // Запускаем при загрузке DOM
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', applyDynamicContent);
    } else {
      applyDynamicContent();
    }
    

    Как это работает:

    • Конфиг contentConfig хранит все варианты контента, привязанные к ключам (в примере - названиям брендов)
    • Функция parseUrlParam достаёт значение параметра из URL
    • applyDynamicContent ищет нужные элементы на странице и меняет их содержимое
    • Скрипт срабатывает, как только браузер прочитал DOM

    Подмена по геолокации и источнику трафика

    Часто нужно подменять контент не только по UTM, но и по тому, откуда пришёл посетитель. Например, из поиска Яндекса - одна версия, из контекстной рекламы Google Ads - другая.

    Даннные о источнике можно получить из document.referrer - это URL страницы, с которой пришёл пользователь. Если referrer содержит слово ‘google’, значит пришёл из поиска Google. Если ‘yandex’ - из Яндекса.

    const refererConfig = {
      'google': {
        title: 'Быстрая доставка от Google',
        cta: 'Поиск нашел вас!'
      },
      'yandex': {
        title: 'Проверено Яндексом',
        cta: 'Популярно в Яндексе'
      },
      'facebook': {
        title: 'Спецпредложение из Facebook',
        cta: 'Рекомендуется друзьями'
      }
    };
    
    function applyByReferrer() {
      const referrer = document.referrer.toLowerCase();
      let matchedConfig = null;
      
      for (const [source, config] of Object.entries(refererConfig)) {
        if (referrer.includes(source)) {
          matchedConfig = config;
          break;
        }
      }
      
      if (matchedConfig) {
        document.querySelector('h1').textContent = matchedConfig.title;
        document.querySelector('.cta-text').textContent = matchedConfig.cta;
      }
    }
    
    applyByReferrer();
    

    Это помогает, когда вы запускаете кампании в разных каналах и каждому нужно говорить по-своему:

    • Из поиска - акцент на решение проблемы
    • Из соцсетей - акцент на скорость и удобство
    • Из объявлений - акцент на цену или срок

    Продвинутый вариант: JSON-конфиг и асинхронная загрузка

    Если кейсов много и скрипт становится громоздким, можно вынести конфиг в отдельный JSON-файл. Это удобнее для обновления и масштабирования.

    // Загружаем конфиг из файла
    fetch('/config/dynamic-content.json')
      .then(response => response.json())
      .then(config => {
        const utm = parseUrlParam('utm_source');
        if (utm && config[utm]) {
          applyContent(config[utm]);
        }
      })
      .catch(error => console.warn('Config load failed:', error));
    
    function applyContent(data) {
      Object.keys(data).forEach(selector => {
        const element = document.querySelector(selector);
        if (element) {
          element.textContent = data[selector];
        }
      });
    }
    

    JSON-файл выглядит так:

    {
      "fanuc": {
        ".hero h1": "Запчасти Fanuc: быстро и надежно",
        ".hero p": "Оригинал с гарантией 2 года",
        ".cta-button": "Заказать Fanuc"
      },
      "siemens": {
        ".hero h1": "Решения Siemens для вашего производства",
        ".hero p": "Полная совместимость со всеми моделями",
        ".cta-button": "Запросить S7"
      }
    }
    

    Преимущество такого подхода:

    • Разделение: логика остаётся в JavaScript, данные - в отдельном файле
    • Масштабируемость: легко добавлять новые кейсы без изменения кода
    • Кэширование: браузер кэширует JSON, отдельный запрос работает быстро
    • A/B-тестирование: можно менять контент на бэкенде, не трогая фронт

    Чек-лист: как правильно внедрить

    Прежде чем запускать в боевых условиях, проверь эти моменты:

    • Селекторы должны быть уникальными: используй data-* атрибуты или специальные классы типа .dynamic-title, не ловишь по общим .h1 или .text
    • Проверь наличие элемента: перед тем как менять, убедись, что элемент вообще есть на странице (if (element))
    • Тестируй на разных браузерах: особенно на старых версиях Safari и IE, если ещё поддерживаешь
    • Следи за производительностью: не заставляй скрипт перерисовывать весь DOM, парсь только нужное
    • Логируй ошибки: добавь console.error для дебага, но удали перед продакшеном
    • Версионируй конфиг: если меняешь структуру, добавь версию в JSON
    Пункт Что проверить Зачем
    Селекторы Элементы находятся Скрипт не будет ловить нужные элементы
    Параметры URL Названия совпадают с кейсами Подмена не сработает без совпадения
    Производительность Скрипт не блокирует рендер Страница не будет тормозить
    Fallback Базовый контент загружается Если подмена не сработала, пользователь видит что-то
    Кроссбраузерность Работает в Chrome, Firefox, Safari Теряешь часть аудитории в IE

    На что ещё обратить внимание

    Забывают про важный момент: кэширование браузером. Если у пользователя уже кэширована старая версия страницы, новый скрипт может не загрузиться. Добавь версию в URL скрипта или используй cache-busting параметры.

    Ещё один подводный камень - производительность на мобильных. Не усложняй конфиг, иначе на старых Android-телефонах скрипт будет исполняться долго и замораживать интерфейс. Лучше использовать простые селекторы и минимум условий.

    И последнее - совместимость с фреймворками. Если сайт написан на React, Vue или Angular, прямое манипулирование DOM может сломать реактивность. В таких случаях лучше передать данные подмены через props или store, чтобы фреймворк сам перерисовал компоненты.

    Всё остальное - дело опыта. Запускайте на малом трафике, смотрите метрики, итерируйте. Конверсия обычно растёт на 20-40% даже с базовой подменой, потому что люди видят именно то, что ищут.

  • Tekla Structure - скачать 2026

    ПO для чпу
    1
    4
    0 Голоса
    1 Сообщения
    4 Просмотры
    Нет ответов
  • Node.js скрипт для мониторинга PLC сигналов ЧПУ с Telegram алертами

    ПO для чпу node.js plc мониторинг telegram алерты
    1
    0 Голоса
    1 Сообщения
    90 Просмотры
    Нет ответов
  • Node.js скрипт: парсинг DXF в G-код с выгрузкой в Excel для ЧПУ

    ПO для чпу dxf парсер g-код node.js чпу excel
    2
    0 Голоса
    2 Сообщения
    161 Просмотры
    kirilljsxK
    DXF-parser доступен через npm - https://www.npmjs.com/package/dxf-parser
  • Python-скрипт для отправки G-кода на ЧПУ через COM-порт с проверкой отклика

    ПO для чпу python чпу g-code serial порт
    1
    0 Голоса
    1 Сообщения
    108 Просмотры
    Нет ответов
  • 0 Голоса
    1 Сообщения
    100 Просмотры
    Нет ответов
  • ИИ-генерация G-кода для ЧПУ: оптимизация без ручной доработки

    ПO для чпу ии чпу g-код оптимизация
    3
    0 Голоса
    3 Сообщения
    622 Просмотры
    kirilljsxK
    @павел-0 said: Нужно из детали 60x60x30 сделать деталь 50x50X20 какая программа фреза 20 скорость 6400 Добрый день! давайте разбираться шаг за шагом Важно! Сначала перед использованием применяйте тестовый режим! Сначала задаем режимы, включаем шпиндель и подводим фрезу к началу координат. G90 G17 G54 ; Абсолютная система координат, выбор плоскости XY, выбор системы координат[reference:6] M03 S6400 ; Включить шпиндель на 6400 об/мин G00 Z5.0 ; Быстро поднять фрезу на 5 мм над деталью G00 X-10.0 Y-10.0 ; Быстро переместить фрезу в точку старта (за пределами заготовки) Далее подрезаем верх- снимаем 10 мм по Z #1 = 0.0 ; Начальная глубина (Z=0 — это верх заготовки) #2 = -10.0 ; Конечная глубина (врезаемся в деталь на 10 мм) #3 = -1.0 ; Шаг по глубине за один проход (1 мм) WHILE [#1 GT #2] DO1 ; Цикл, который выполняется, пока мы не достигнем конечной глубины #1 = #1 + #3 ; Увеличиваем глубину на шаг IF [#1 LT #2] THEN #1 = #2 ; Если шаг слишком большой, фиксируем финальную глубину G01 Z#1 F200 ; Врезаемся на новую глубину с рабочей подачей G01 X70.0 F500 ; Фрезеруем по оси X до 70 мм (за край заготовки) G00 Y10.0 ; Быстро поднимаем фрезу и переходим на следующую "дорожку" G01 X-10.0 F500 ; Фрезеруем в обратную сторону G00 Y20.0 ; Переходим на следующую дорожку END1 ; Конец цикла G00 Z5.0 ; Быстрый отвод фрезы вверх в конце цикла Пояснение: Фреза будет двигаться змейкой, снимая слой за слоем. Этот код отлично подходит для начала. Теперь углубляем центральную часть до 20 мм. Фактически, мы повторяем тот же принцип «змейки», но в ограниченной области. #1 = 0.0 ; Текущая глубина (от верха) #2 = -10.0 ; Глубина кармана (10 мм от верха) #3 = -1.0 ; Шаг по глубине (1 мм) WHILE [#1 GT #2] DO2 ; Запускаем цикл по глубине #1 = #1 + #3 IF [#1 LT #2] THEN #1 = #2 G01 Z#1 F200 ; Врезаемся на новую глубину G01 X0.0 F500 ; Начинаем фрезеровать от X=0 до X=50 G01 Y5.0 ; Смещаемся для следующего прохода (5 мм — это ~1/4 диаметра фрезы[reference:8]) G01 X50.0 G01 Y10.0 G01 X0.0 ; ... и так далее, пока не обработаем всю площадь 50x50 мм ... END2 G00 Z5.0 Пояснение: Этот цикл будет последовательно обрабатывать всю область кармана (50x50 мм) на заданную глубину. M05 ; Остановить шпиндель M30 ; Конец программы И еще раз повторюсь! Важное примечание по безопасности: Всегда проверяйте новые программы в режиме сухого прогона (без заготовки) и убедитесь, что ваша станочная система (Fanuc, HAAS, Mach3 и т.д.) использует те же самые коды и синтаксис!
  • 0 Голоса
    1 Сообщения
    82 Просмотры
    Нет ответов
  • Постпроцессоры SolidCam - Сборник

    Перенесена ПO для чпу
    9
    2 Голоса
    9 Сообщения
    3k Просмотры
    I
    @kirilljsx Буду очень благодарен . Всё, что связано с токарными Sinumerik 808 или 828, было бы очень здорово.