Рефакторинг существующего кода

Рефакторинг кода, использующего Smooth Scroll, начинается с детального анализа существующей реализации. Основное внимание уделяется:

  • дублирующимся обработчикам событий
  • избыточным вызовам инициализации
  • жестко закодированным селекторам
  • отсутствию конфигурации и масштабируемости

Типичный пример «сырого» кода:

document.querySelectorAll('a[href^="#"]').forEach(anchor => {
  anchor.addEventListener('click', function (e) {
    e.preventDefault();

    document.querySelector(this.getAttribute('href')).scrollIntoView({
      beh * avior: 'smooth'
    });
  });
});

Недостатки:

  • отсутствие обработки ошибок (например, если элемент не найден)
  • невозможность гибкой настройки поведения
  • повторное навешивание обработчиков при динамическом обновлении DOM

Выделение конфигурации

Жестко заданные параметры следует вынести в конфигурационный объект. Это упрощает поддержку и масштабирование.

const scrollConfig = {
  selector: 'a[href^="#"]',
  beh * avior: 'smooth',
  block: 'start'
};

Использование:

document.querySelectorAll(scrollConfig.selector).forEach(anchor => {
  anchor.addEventListener('click', function (e) {
    e.preventDefault();

    const target = document.querySelector(this.getAttribute('href'));
    if (!target) return;

    target.scrollIntoView({
      beh * avior: scrollConfig.behavior,
      block: scrollConfig.block
    });
  });
});

Преимущества:

  • централизованное управление параметрами
  • упрощение тестирования
  • повышение читаемости

Инкапсуляция логики

Разрозненный код заменяется модульной структурой. Логика прокрутки выносится в отдельную функцию или класс.

Функциональный подход

function smoothScrollTo(targetSelector, options = {}) {
  const element = document.querySelector(targetSelector);
  if (!element) return;

  element.scrollIntoView({
    beh * avior: options.behavior || 'smooth',
    block: options.block || 'start'
  });
}

Использование:

document.addEventListener('click', function (e) {
  const anchor = e.target.closest('a[href^="#"]');
  if (!anchor) return;

  e.preventDefault();
  smoothScrollTo(anchor.getAttribute('href'));
});

Преимущества:

  • повторное использование
  • упрощение тестирования
  • уменьшение связности

Делегирование событий

Вместо навешивания обработчика на каждый элемент используется делегирование:

document.addEventListener('click', function (e) {
  const link = e.target.closest('a[href^="#"]');
  if (!link) return;

  e.preventDefault();

  const targetId = link.getAttribute('href');
  const target = document.querySelector(targetId);

  if (!target) return;

  target.scrollIntoView({ beh * avior: 'smooth' });
});

Преимущества:

  • меньше обработчиков → выше производительность
  • корректная работа с динамически добавленными элементами
  • упрощение структуры кода

Работа с библиотекой Smooth Scroll

При использовании сторонней библиотеки (например, Smooth Scroll), часто встречается неструктурированная инициализация:

var scroll = new SmoothScroll('a[href*="#"]', {
  speed: 300
});

Рефакторинг предполагает:

1. Вынос настроек

const smoothOptions = {
  speed: 500,
  offset: 80,
  easing: 'easeInOutCubic'
};

2. Централизованная инициализация

function initSmoothScroll(options) {
  return new SmoothScroll('a[href*="#"]', options);
}

const scrollInstance = initSmoothScroll(smoothOptions);

Устранение магических значений

Часто в коде встречаются «магические числа»:

offset: 80

Рефакторинг:

const HEADER_HEIGHT = 80;

const smoothOptions = {
  speed: 500,
  offset: HEADER_HEIGHT
};

Преимущества:

  • понятность
  • легкость изменения
  • уменьшение ошибок

Разделение ответственности

Смешивание логики прокрутки и UI-логики ухудшает поддержку:

Плохой пример:

anchor.addEventListener('click', function (e) {
  e.preventDefault();
  document.body.classList.remove('menu-open');
  document.querySelector(this.getAttribute('href')).scrollIntoView({
    beh * avior: 'smooth'
  });
});

Рефакторинг:

function closeMenu() {
  document.body.classList.remove('menu-open');
}

function handleAnchorClick(e) {
  const link = e.target.closest('a[href^="#"]');
  if (!link) return;

  e.preventDefault();
  closeMenu();
  smoothScrollTo(link.getAttribute('href'));
}

document.addEventListener('click', handleAnchorClick);

Преимущества:

  • независимость компонентов
  • повторное использование функций
  • улучшение тестируемости

Обработка ошибок и граничных случаев

Рефакторинг должен учитывать нестандартные ситуации:

function smoothScrollTo(selector) {
  if (!selector || selector === '#') return;

  const element = document.querySelector(selector);

  if (!element) {
    console.warn(`Элемент ${selector} не найден`);
    return;
  }

  element.scrollIntoView({ beh * avior: 'smooth' });
}

Добавляется:

  • проверка входных данных
  • логирование ошибок
  • защита от некорректных селекторов

Оптимизация производительности

Избежание лишних вычислений

const anchors = document.querySelectorAll('a[href^="#"]');

Лучше:

  • использовать делегирование
  • минимизировать обращения к DOM

Кэширование элементов

const cache = new Map();

function getElement(selector) {
  if (!cache.has(selector)) {
    cache.set(selector, document.querySelector(selector));
  }
  return cache.get(selector);
}

Поддержка пользовательских настроек

Добавление возможности переопределения параметров:

function createSmoothScroll(customOptions = {}) {
  const defaultOptions = {
    speed: 500,
    offset: 0
  };

  const options = { ...defaultOptions, ...customOptions };

  return new SmoothScroll('a[href*="#"]', options);
}

Рефакторинг в сторону классов

При усложнении логики предпочтителен объектно-ориентированный подход:

class SmoothScrollManager {
  constructor(options = {}) {
    this.options = {
      speed: 500,
      offset: 0,
      ...options
    };

    this.instance = null;
  }

  init() {
    this.instance = new SmoothScroll('a[href*="#"]', this.options);
  }

  destroy() {
    if (this.instance) {
      this.instance.destroy();
      this.instance = null;
    }
  }

  update(options) {
    this.destroy();
    this.options = { ...this.options, ...options };
    this.init();
  }
}

Преимущества:

  • контроль жизненного цикла
  • удобство масштабирования
  • возможность расширения

Итоговые принципы рефакторинга

  • устранение дублирования
  • разделение логики
  • внедрение конфигурации
  • использование делегирования событий
  • защита от ошибок
  • улучшение читаемости
  • подготовка к масштабированию

Код после рефакторинга становится:

  • предсказуемым
  • расширяемым
  • устойчивым к изменениям
  • удобным для поддержки в крупных проектах