티스토리 게시글 목차 만들기✍️

🎁 Index

내가 쓴 포스팅을 가끔 참고할 일이 생긴다.

원하는 부분만 슥삭쇽 찾아서 보고싶은데, 포스팅이 길다보니 계속 스크롤을 내려서 찾아줘야 했다.

 

벨로그는 자동으로 목차를 생성해주는 것 같던데...

목 마른 자가 우물 판다고 바로 만들어보았다😀

 

⛏️ 목표는 이런 목차를 만드는 거였다.

  • 포스트 옆 오른쪽 상단 빈 영역에 목차가 생긴다.
  • 스크롤을 내려도 목차는 같은 위치에 고정되어 있다.
  • 페이지가 너무 좁거나 스크롤이 포스트 영역을 벗어나면 목차는 나타나지 않는다.
  • 제목1, 제목2에 대해 목차가 생긴다.
  • 목차를 누르면 해당 소제목으로 스크롤이 이동한다.
  • 스크롤을 내리면 목차에서 내가 현재 위치하고 있는 소제목에 강조 효과가 생긴다.

👉 목차 영역 생성

HTML

목차로 만들어줄 #index를 생성한다.

#index 안에는 .item이 소제목으로 들어간다.

<s_permalink_article_rep>
    <div id="index">
    </div>
    ...

CSS

slideToggle()을 통해 동작할 것이므로 display 속성을 none으로 설정해준다.

#index {
	display: none;
	position: fixed;
	width: 180px;
	max-height: 300px;
	top: 60px;
	right: 20px;
	z-index: 999;
	border-left: 2px solid #eee;
	padding-left: 12px;
	overflow: scroll;
}

 

브라우저 크기가 작아지면 가독성을 위해 목차는 아예 보이지 않아야 한다.
스킨의 포스트 영역 크기에 따라 재량껏 선택해준다.

@media screen and (max-width:1279px) {
	.index { display: none !important; }
}

 

제목2 즉 h3에는 sub 클래스를 추가해 제목1과 차별화할 것이다.

sub 클래스의 스타일을 정의해주자.

#index .item {
	height: 20px;
	font-size: 12px;
	color: #555;
	line-height : 20px;
	padding-left: 4px;
	padding-right: 8px;
	cursor: pointer;
	white-space: nowrap;
	overflow:hidden;
	text-overflow: ellipsis;
}
#index .item.sub {
	padding-left: 12px;
}

 

현재 위치하고 있는 소제목에는 selected 클래스를 추가해 강조 효과를 줄 것이다.

selected 클래스의 스타일도 정의해준다.

#index .selected {
	font-size: 13px;
	font-weight: 500;
	padding-left: 0px;
	color: #222;
	transition: 0.2s ease !important;
}
#index .sub.selected {
	padding-left: 4px;
}

👉 목차 요소 생성

게시글에서 제목1, 제목2에 해당하는 텍스트들을 목차로 만들어줄 것이다.

티스토리에서는 h2, h3 태그가 이에 해당한다.

각각의 소제목을 클릭하면 해당 위치로 이동하는 클릭 이벤트를 넣어주었다.

$('.entry-content h2, .entry-content h3').each(function (index, item) {
    var offset = $(this).offset();	// 요소 위치 좌표
    var text = $(this).html().replace(/\<b\>|\<\/b\>/gm, "");	// 소제목 텍스트
    var div = $("<div class='item'>"+text+"</div>").on("click", function() {
            $('html').animate({scrollTop : offset.top}, 0);
        });
    if($(this).prop('tagName')=="H3") {
        div.addClass("sub");
    }
    $("#index").append(div);
});

👉 페이지 로드

처음 페이지가 로드되면, 스크롤의 위치가 포스트 영역에 있는지 판단해 목차를 보여줄지 말지 결정해야 한다.

또한 목차를 보여준다면 어떤 소제목에 강조 효과를 줄지 판단해야 한다.

var isToggle = false;	// 토글이 열렸는지 닫혔는지 나타내는 변수
var before = 0;	// 마지막 스크롤 직전의 스크롤 위치
var after = 0;	// 마지막 스크롤 후의 스크롤 위치

// 포스트 영역 내에 있으면 목차를 보여준다
if ($('html').scrollTop>$(".entry-content").offset().top && $('html').scrollTop<$(".comment-form").offset().top-200) {
    $("#index").slideToggle(300);
    isToggle = true;
    
    // 현재 스크롤 위치에 해당하는 소제목을 찾고 그 소제목에 강조효과를 준다
    $('.entry-content h2, .entry-content h3').each(function (index, item) {
        var pos = document.documentElement.scrollTop;
        var offset = $(this).offset().top;
        if(pos+100>=offset) {
            before = index;
        }
    });
    $("#index .item").removeClass("selected");
    $("#index .item").eq(before).addClass("selected");
}

👉 스크롤 이벤트

스크롤이 발생하면 목차 보여주기 여부, 소제목 강조 여부, 목차 스크롤 여부를 결정한다.

자세한 사항은 각주를 통해 정리했다.

// 스크롤시
window.addEventListener('scroll', () => {
    var pos = document.documentElement.scrollTop;
    var after = 0;

    // 스크롤 위치가 포스트 영역 내에 있을 경우
    if(pos>$(".entry-content").offset().top && pos<$(".comment-form").offset().top-200) {
        if(!isToggle) {
            $("#index").slideToggle(300);
            isToggle = true;
        }
        $('.entry-content h2, .entry-content h3').each(function (index, item) {
            if(pos+100>=$(this).offset().top) {
                after = index;
            }
        });
        if(before!=after) {
            // 목차 소제목 강조효과 재설정
            $("#index .item").removeClass("selected");
            $("#index .item").eq(after).addClass("selected");
            // 목차 내에 스크롤이 있는 경우 목차 이동에 따라 자연스럽게 스크롤도 내려줌줌
            if(after/$("#index .item").length<=0.25) {
                $("#index").animate({scrollTop : 0}, 200);
            } else if(after/$("#index .item").length>=0.75) {
                $("#index").animate({scrollTop : 280}, 200);
            } else {
                $("#index").animate({scrollTop : 280*after/$("#index .item").length}, 200);
            }
            before = after;
        }
    // 스크롤 위치가 포스트 영역 밖에 있을 경우
    }	else {
        if(isToggle) {
            $("#index").slideToggle(300);
            isToggle = false;
        }
    }
});

🐰

결과적으로 이렇게 예쁜 목차가 완성됐다❣️

포스팅 가독성에 큰 도움이 될 것 같다🥰