Почему JavaScript не мгновенно отслеживает изменения URL в адресной строке?

Как можно изменить страницу "auth.php" динамически при нажатии на ссылки "sign up" и "log in", которые ведут на эту же страницу, добавляя к ссылкам хэштеги "#login" и "#signup"?
  • 1 ноября 2023 г. 10:48
Ответы на вопрос 2
JavaScript не мгновенно отслеживает изменения URL в адресной строке из соображений безопасности и производительности. Если JavaScript мог бы мгновенно реагировать на каждое изменение URL, это создало бы потенциальные уязвимости для атак, таких как перехват данных или манипуляции с содержимым страницы.

Однако, можно использовать событие `hashchange` для отслеживания изменений хэштега в адресной строке. Это событие срабатывает, когда часть URL после символа `#` изменяется.

Чтобы изменить страницу "auth.php" динамически при нажатии на ссылки "sign up" и "log in", можно написать следующий код JavaScript:

```javascript
// Функция для обработки изменений хэштега
function handleHashChange() {
  var hash = location.hash; // Получаем текущий хэштег из адресной строки

  // Если хэштег равен "#login", выполняем нужные действия
  if (hash === '#login') {
    // Изменяем страницу "auth.php" для входа пользователя
  }

  // Если хэштег равен "#signup", выполняем нужные действия
  if (hash === '#signup') {
    // Изменяем страницу "auth.php" для регистрации пользователя
  }
}

// Назначаем обработчик события "hashchange"
window.addEventListener('hashchange', handleHashChange);

// Вызываем обработчик события в первый раз для текущего хэштега в адресной строке
handleHashChange();
```

Затем, в ссылках "sign up" и "log in" можно добавить хэштеги следующим образом:

```html
<a href="auth.php#login">log in</a>
<a href="auth.php#signup">sign up</a>
```

Обратите внимание, что изменение хэштега в адресной строке не перезагружает страницу полностью, поэтому вам нужно будет обновить содержимое страницы с помощью JavaScript в обработчике события `hashchange`.
Изменение события на hashchange:

['DOMContentLoaded', 'hashchange'].forEach((event) => {
  window.addEventListener(event, () => {
    document.getElementById('loginSection')?.style.setProperty('display', 'none');
    document.getElementById('signupSection')?.style.setProperty('display', 'none');
    document.getElementById(`${location.hash.slice(1)}Section`)?.style.removeProperty('display');
  });
});

Более гибкий вариант:

Если ключ в хэше не совпадает ни с одним блоком, то текущий блок не будет скрыт. Код будет выполняться не только при изменении хэша, но и после инициализации страницы (с проверкой, загружена ли уже сейчас страница).

const getBlocks = () => ({
  login: document.getElementById('loginSection'),
  signup: document.getElementById('signupSection'),
});

const updateBlocks = (href) => {
  const url = new URL(href);
  const hash = url.hash.slice(1);
  const blocks = getBlocks();
  if (hash in blocks === false) {
    return;
  }
  
  for (const key in blocks) {
    blocks[key]?.style.setProperty('display', 'none');
  }

  blocks[hash]?.style.removeProperty('display');
};

window.addEventListener('hashchange', (event) => {
  updateBlocks(event.newURL);
});

if (document.readyState === 'interactive' || document.readyState === 'complete') {
  updateBlocks(location.href);
} else {
  window.addEventListener('DOMContentLoaded', () => {
    updateBlocks(location.href);
  });
}

Вариант без for:

const getBlocks = () => ({
  login: document.getElementById('loginSection'),
  signup: document.getElementById('signupSection')
});

const updateBlocks = (href) => {
  const url = new URL(href);
  const blocks = getBlocks();
  const hash = url.hash.slice(1);
  if (hash in blocks === false) {
    return;
  }
  
  blocks.login.style.setProperty('display', 'none');
  blocks.signup.style.setProperty('display', 'none');
  blocks[hash]?.style.removeProperty('display');
};

window.addEventListener('hashchange', (event) => {
  updateBlocks(event.newURL);
});

if (
  document.readyState === 'interactive' ||
  document.readyState === 'complete'
) {
  updateBlocks(location.href);
} else {
  window.addEventListener('DOMContentLoaded', () => {
    updateBlocks(location.href);
  });
}
Похожие вопросы