Що це?
На деяких сайтах періодично можна зустріти щось подібне:
Працює ця штука так:
- Кожен пункт вмісту – це заголовок статті h2, h3, h4…
- Клікаючи на якийсь із цих пунктів ми переміщуємося за допомогою якірного посилання в необхідну нам область сторінки.
- Також, коли ми перегортаємо сторінку і в поле зору користувача потрапляє певна область із заголовком, цей пункт навігації якимось чином підсвічується, даючи зрозуміти де ми знаходимося.
Завантажити готовий файл можна за цією посиланням
Як це працює?
А тепер розберемо все поетапно. Збиратимемо файл скрипта по шматках.
Розмітка нашої навігації буде виглядати так:
<ul>
<li>
<a href="#article_title1">Title H2</a>
<ul>
<li>
<a href="#article_title2">Title H3</a>
</li>
<li>
<a href="#article_title3">Title H4</a>
</li>
</ul>
</li>
<li>
<a href="#article_title4">Title H2</a>
<ul>
<li>
<a href="#article_title5">Title H3</a>
</li>
<li>
<a href="#article_title6">Title H4</a>
</li>
</ul>
</li>
</ul>
Як видно з прикладу, наша навігація матиме вкладеність.
1) Створюємо змінну, в яку поміщаємо заголовки контенту необхідної нам області:
const titles = document.querySelector('.post-content__content .text').querySelectorAll('h2,h3,h4');
2) Додаємо до наших заголовків id:
let i = 0;
titles.forEach(title=>{
title.setAttribute('id', `articles_title${i}`);
i++;
});
3) Створюємо об’єкт та змінну, які допоможуть нам зробити вкладеність
let titlesObj = {},
h2;
for(let i = 0; i < titles.length; i++){
if(titles[i].classList.contains('no-active')){
continue;
}
if(titles[i].tagName == 'H2'){
titlesObj[titles[i].textContent] = {
'id': titles[i].getAttribute('id')
};
if(titles[i+1] && titles[i+1].tagName != 'H2'){
h2 = titles[i].textContent;
titlesObj[titles[i].textContent]['titles'] = {};
}
}
if(titles[i].tagName != 'H2'){
titlesObj[h2]['titles'][titles[i].textContent] = {
'id': titles[i].getAttribute('id')
}
}
}
4) Створюємо структуру нашого вмісту
let navigation = '';
for(let item in titlesObj){
let subLinks = '';
if(titlesObj[item]['titles']){
subLinks = subLinks + '<ul>';
for(let sub in titlesObj[item]['titles']){
subLinks = subLinks + `<li><a href="#${titlesObj[item]['titles'][sub]['id']}">${sub}</a></li>`;
}
subLinks = subLinks + '</ul>';
}
navigation = navigation + `<li><a href="#${titlesObj[item]['id']}">${item}</a>${subLinks}</li>`;
}
5) Додаємо розмітку навігації у необхідну нам область
document.querySelector('#articles_nav ul').innerHTML = navigation;
6) Створюємо та викликаємо функцію яка буде:
– плавно переміщати сторінку в область із заголовком при натисканні на пункт навігації.
– підсвічуватиме потрібний пункт меню при скролі сторінки.
postContentNavigation();
function postContentNavigation(){
// 6.1) Заносимо всі посилання навігації до змінної
const smoothLinks = document.querySelectorAll('#articles_nav a');
if(smoothLinks){
// 6.2) Навішуємо на кожне посилання подія кліка
for (let smoothLink of smoothLinks) {
smoothLink.addEventListener('click', function (e) {
e.preventDefault();
const id = smoothLink.getAttribute('href');
document.querySelector(id).scrollIntoView({
behavior: 'smooth',
block: 'start'
});
});
};
// 6.3) Підсвічуємо пункти меню
$(window).scroll(function(){
var $sections = $('.post-content__content h2, .post-content__content h3, .post-content__content h4');
$sections.each(function(i,el){
var top = $(el).offset().top-50;
var bottom = top +$(el).height();
var scroll = $(window).scrollTop();
var id = $(el).attr('id');
if( scroll > top && scroll < bottom){
$('li.active').removeClass('active');
$('a[href="#'+id+'"]').parents('li').addClass('active');
}
});
});
}
}