일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- abstract
- array
- ArrayList
- Class
- collection
- coposition api
- csr
- database
- db
- DDL
- default
- DML
- Exception
- Generic
- HashSet
- Interface
- Java
- Java 입문
- java 자료형
- java 클래스
- JavaBean
- javabeans
- JAVA의 특징
- JSESSIONID
- LinkedList
- linkedset
- list
- mariadb
- Mpa
- Mustache
- Today
- Total
GeehDev
[티스토리] 게시글 내 목차 만들기 본문
Index
개요
✅기능
- 게시글 내 h태그를 이용하여 목차를 자동 생성할 수 있고
- 각 각 목차를 클릭 시 해당 내용으로 이동하도록 (id와 a태그의 href="#아이디" 방식 사용)
- 현재 스킨이 반응형이기 때문에 그에 따라 목차도 반응형으로 구성 (접이식 목차 / 기본목차)
✅ 방식
- 게시글 작성 시 제목1, 제목2, 제목3 (h태그)를 사용하여 구현 예정
- 티스토리 내 스킨편집과 서식 기능을 이용해서 구현 예정 - html / css / js 작성
목차를 만드려는 이유
기존 velog에서 티스토리로 이사 오면서 여러 가지 차이점과, 각 각의 장단점을 느꼈었습니다.
그중 velog에서는 마크다운 문법으로 글을 작성하면 알아서 목차가 구성되는데, 티스토리의 경우 스킨에 따라 목차가 있을 수 있지만, 제가 택한 스킨에는 없어서 이번 기회에 추가해 보기로 했습니다.
여러 가지 글들을 찾아봤지만, 그냥 티스토리 내 스킨편집 기능을 이용해 스스로 작업해보려고 합니다.(스스로 불러온 재앙...)
작업 진행
1. HTML작성
목차 HTML 을 작성합니다.
해당 HTML 목차는 티스토리 스킨편집에서 게시글 본문에 해당하는 위치를 확인하고 해당 위치에 넣어줄 예정
<!-- 목차 영역 made by GeehDev -->
<div id="indexArea" class="index-area">
<!-- 목차 제목 made by GeehDev -->
<h3 class="index-area-title">목차</h2>
<!-- // 목차 제목 made by GeehDev -->
<!-- 목차 내용 made by GeehDev -->
<ul class="index-area-contents"></ul>
<!-- // 목차 내용 made by GeehDev -->
</div>
<!-- // 목차 영역 made by GeehDev -->
2. CSS 작성
CSS는 저는 우선 간단하게 구성했습니다.
- 접이식 목차 (우측에 고정되어 있으면서 펼쳐서 보거나 접어놓거나 할 수 있도록)
- 기본 목차 (게시글 상단에 위치)
/* 목차 컨테이너 스타일 */
#indexArea {
border: 1px solid #efefef;
border-radius: 10px;
padding: 10px 25px;
box-sizing: border-box;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
background-color: #fff;
width: 400px;
z-index: 100;
font-size: 15px;
position: fixed;
top: 100px;
right: -400px; /* 기본적으로 숨김 */
transition: all 0.3s ease-in-out;
}
/* 열렸을 때의 상태 */
#indexArea.open {
right: 10px; /* 나타나게 함 */
}
/* 목차 제목 */
#indexArea > .index-area-title {
font-weight: bold;
}
/* 목차 구분선 */
#indexArea h4 {
margin: 5px 0;
padding: 0 5px;
color: #b3b3b3;
}
#indexArea h4::after {
content: "";
display: block;
height: 1px;
background-color: #ccc;
margin-top: 10px;
}
/* 목차 리스트 스타일 */
#indexArea ul {
padding: 0;
}
#indexArea ul li {
list-style-type: none;
margin: 0;
line-height: 1.8;
}
/* 목차 링크 스타일 */
#indexArea ul li a {
color: #555;
text-decoration: none;
transition: all 0.2s ease;
}
#indexArea ul li a:hover {
color: #6bacce;
}
#indexArea ul li a.active {
text-decoration: underline;
color: #6bacce;
font-weight: bold;
}
/* 활성화된 목차 항목 앞에 강조 바 */
#indexArea ul li a.active::before {
content: "";
display: inline-block;
height: 10px;
width: 5px;
background-color: #6bacce;
margin-right: 5px;
}
/* 깊이에 따른 들여쓰기 적용 */
#indexArea ul li.depth1 {
font-weight: bold;
}
#indexArea ul li.depth2 {
margin-left: 1.5em;
}
#indexArea ul li.depth3 {
margin-left: 3em;
}
/* 목차 토글 버튼 */
.index-toggle-btn {
position: fixed;
top: 100px;
right: 10px;
background-color: #6bacce;
color: #fff;
padding: 5px 10px;
border-radius: 5px;
cursor: pointer;
font-size: 12px;
z-index: 101;
transition: all 0.3s ease-in-out;
}
.index-toggle-btn.hidden {
right: -50px; /* 숨김 */
}
/* 반응형 설정 */
@media (max-width: 1500px) {
#indexArea {
position: relative;
right: 0;
top: 0;
width: 100%;
margin: 0 auto;
}
.index-toggle-btn {
display: none;
}
}
3. JS작성
페이지를 로딩하면서 작성한 게시글의 html을 읽어와서 h태그들을 목차로 생성해 줄 js를 작성해 줌
각 함수와 구조는 주석으로 작성해 놨습니다.
/**
* IndexGenerator 모듈
* 블로그 게시글에서 h1, h2, h3 태그를 찾아 목차를 자동으로 생성
*/
const IndexGenerator = (function() {
const targetSelector = '#article-view > .contents_style';
const targetHeading = ['h1', 'h2', 'h3'];
let headings;
/****************************************
* 초기화 관련
* - init : 모듈 초기화
* - initField : 필드 초기화
* - gernerateComponets : 컴포넌트 생성
* - bindEvents : 이벤트 바인딩
****************************************/
const init = function() {
initField();
if(headings && headings.length > 0) {
generateComponents();
bindEvents();
}
};
const initField = function() {
headings = UTILS.getHeadings(targetSelector, targetHeading);
};
const generateComponents = function() {
INDEX.gernerateIndex();
};
const bindEvents = function() {
EVENTS.bindEvents();
};
/****************************************
* UTIL 관련 메서드
****************************************/
const UTILS = {
/**
* Heading 태그 가져오는 함수
* @param {string} targetSelector - 헤딩을 검색할 대상 요소의 선택자 : 게시글 본문 선택자자
* @param {Array<string>} targetHeading - 검색할 헤딩 태그 리스트 : h1, h2, h3
* @returns {Array<Element>} - 찾은 헤딩 요소들의 배열
*/
getHeadings: function(targetSelector, targetHeading) {
let result = [];
const contents = document.querySelector(targetSelector);
if(contents) {
const headingTags = contents.querySelectorAll(targetHeading.join(','));
headingTags.forEach(el => result.push(el));
}
return result;
},
/**
* 문자열 공란 체크 함수
* @param {string} str - 문자열
* @returns {boolean} - 공란일 경우 true, 공란이 아닐경우 false
*/
isEmpty: function(str) {
return !str || str.replace(/ /g, '').trim().length === 0;
},
/**
* heading 태그에 따라 depth 클래스 반환하는 함수
* @param {string} tagName
* @returns {string} - 해당하는 depth 클래스명
*/
getDepthClass: function(tagName) {
switch(tagName) {
case 'H1': return 'depth1';
case 'H2': return 'depth2';
case 'H3': return 'depth3';
default: return 'depth1';
}
},
};
/****************************************
* INDEX 관련 메서드
****************************************/
const INDEX = {
/**
* 목차 생성 함수
*/
gernerateIndex: function() {
INDEX.makeIndexCustom();
INDEX.makeIndexToggleBtn();
INDEX.labelHeadings();
},
/**
* 커스텀 목차 element 만들어서 indexArea에에 넣는 함수
*/
makeIndexCustom: function() {
const indexCustomEl = document.querySelector('#indexArea .index-area-contents');
headings.forEach(el => {
if(!UTILS.isEmpty(el.textContent)) {
let liEl = document.createElement('li');
let aEl = document.createElement('a');
aEl.innerText = el.textContent.trim();
aEl.href = '#' + el.textContent.trim();
liEl.classList.add(UTILS.getDepthClass(el.tagName));
liEl.appendChild(aEl);
indexCustomEl.appendChild(liEl);
}
});
},
/**
* 목차 열기/닫기 토글 버튼 만드는 함수
*/
makeIndexToggleBtn: function() {
const toggleBtn = document.createElement('div');
toggleBtn.classList.add('index-toggle-btn');
toggleBtn.innerText = '< 목차 열기';
document.body.appendChild(toggleBtn);
},
/**
* heading tag에 ID를 라벨링 함수
* */
labelHeadings: function() {
headings.forEach(el => {
el.setAttribute('id', el.textContent.trim());
});
},
};
/****************************************
* EVENT 관련 메서드
****************************************/
const EVENTS = {
/**
* 이벤트 바인드
*/
bindEvents: function() {
const toggleBtn = document.querySelector('.index-toggle-btn');
const indexArea = document.querySelector('#indexArea');
const indexEl = document.querySelectorAll('#indexArea .index-area-contents a');
toggleBtn.addEventListener('click', ()=>{EVENTS.toggleIndexOnOff(toggleBtn, indexArea);});
window.addEventListener('resize', ()=>{EVENTS.checkScreenSize(toggleBtn, indexArea);});
EVENTS.checkScreenSize(toggleBtn, indexArea);
indexEl.forEach(el => {
el.addEventListener('click', ()=>{EVENTS.highlightIndex(indexEl, el);});
});
},
/**
* 화면 사이즈 체크 함수
* 1501 기준으로 접이식 목차, 그 보다 적을 경우는 기본 목차
*/
checkScreenSize: function(toggleBtn, indexArea) {
if (window.innerWidth >= 1501) {
indexArea.classList.remove('open');
toggleBtn.classList.remove('hidden');
} else {
indexArea.classList.add('open');
toggleBtn.classList.add('hidden');
}
},
/**
* 인덱스 목차 열고 닫는 함수
*/
toggleIndexOnOff: function(toggleBtn, indexArea) {
indexArea.classList.toggle('open');
toggleBtn.innerText = indexArea.classList.contains('open') ? '> 목차 닫기' : '< 목차 열기';
},
/**
* 선택된 요소 하이라이트 표시하는 함수수
* @param {Array<Element>} indexEl - 인덱스 각 a 태그 element 리스트트
* @param {element} el - 클릭된 element
*/
highlightIndex: function(indexEl, el) {
indexEl.forEach(other => {
other.classList.remove('active');
});
el.classList.add('active');
}
};
return {
init: () => {init();}
};
})();
// 페이지가 로드될 때 자동으로 IndexGenerator 초기화 실행
/**
* 문서가 완전히 로드된 후 IndexGenerator를 실행한다.
*/
document.addEventListener('DOMContentLoaded', IndexGenerator.init);
4. 블로그 관리에서 서식 입히기
블로그 관리 - 스킨편집 - html 편집 클릭하여 스킨을 편집할 수 있습니다.
1) html 추가하기
html 탭을 클릭하고 본인의 스킨의 html 구조에서 게시글 본문에 해당하는 곳을 찾습니다.
저의 경우는
<s_article_rep>
<s_permalink_article_rep>
<div class="area_view" id="article-view">
내 였습니다.
해당 위치를 찾아서 해당 태그 내 치환자 위쪽으로 만들어둔 html을 넣습니다.
2) css, js 파일 넣기
파일업로드 탭을 클릭하여 [추가]
버튼을 클릭해서 위에 만들어둔 css, js 파일을 업로드합니다.
2) css, js 포함시키기
다시 html 탭을 클릭해서 <head>
태그를 찾습니다.<head>
태그 가장 하위에 방금 업로드한 css, js 경로를 작성합니다.
완성된 모습
- 접이식 목차 - 펼친 상태
- 접이식 목차 - 접힌 상태
- 기복 목차
마치며
velog에서 티스토리로 넘어오면서 스킨에 대해 거의 처음 건드려보는 건데 생각보다 직접 html, css, js를 건들 수 있어서 꽤나 재밌는 시간이었던 것 같습니다.
다만, 앞으로는 여러 금손님들이 만들어두신 여러 가지 좋은 스킨들을 활용하는 게 좋겠다고 생각합니다.🤣
혹시라도....혹시라도 제 글을 보고 직접 작업하시는 분이 계신다면.... 저는 제 스킨에 맞게 css 설정등을 하였으니 이대로 쓰시기에는 아마 안 맞는 부분이 꽤나 있을 것 같습니다.
방식만 참고하시고.... 본인 스킨에 맞춰서 더 멋진 목차를 만드시고.... 저도 알려주셨으면 좋겠습니다.😭😭😭
'Notes > DayLog' 카테고리의 다른 글
[SQLD] 제 54회 합격 수기 (비전공자, 공부기간 1개월, 가채점 92점) (2) | 2024.09.16 |
---|