자동목차구현하기-마크업 언어 h2 태그 아래 목차 넣는 방법(+ JavaScript 코드, css코드 구현하기)

자동목차구현하기-마크업 언어 h2 태그 아래 목차 넣는 방법(+ JavaScript 코드, css코드 구현하기)

계층형 목차 로직을 유지하면서, 요청하신 대로 1. 첫 번째 <h2> 태그 위에 목차를 배치하고 2. 이미지와 유사한 닫힘/펼침 디자인(화살표 토글)을 적용하도록 코드를 수정했습니다.

목차 컨테이너의 모양을 이미지처럼 구현하기 위해 필요한 최소한의 CSS 코드도 함께 제공합니다.

📋 수정된 JavaScript 코드 (첫  h2태그 위 배치 및 화살표 토글)

JavaScript
<script>
//<![CDATA[
// JavaScript를 이용한 자동 목차 생성 로직
function generateTOC() {
    // 1. 블로그 게시물 본문 요소를 찾습니다.
    const postBody = document.querySelector('.post-body') || document.querySelector('.entry-content') || document.querySelector('.post-content');

    // 게시물 본문을 찾지 못하거나 목차 생성 제외 태그가 발견되면 종료
    if (!postBody) return;
    if (postBody.querySelector('.no-toc')) return;


    // 2. H2, H3, H4 태그를 모두 찾습니다. (H1은 게시물 제목이므로 제외)
    const headings = postBody.querySelectorAll('h2, h3, h4');
    if (headings.length < 2) return; // 최소 두 개 이상의 제목이 있어야 목차를 생성합니다.

    // 3. 목차(TOC) 컨테이너 및 토글 영역 생성 (이미지 모양 반영)
    const tocContainer = document.createElement('div');
    tocContainer.id = 'auto-toc-container';
    tocContainer.className = 'toc-box-style'; // CSS 적용을 위한 클래스

    // 3-1. 토글 헤더 영역 (Contents + Arrow) 생성
    const tocToggle = document.createElement('div');
    tocToggle.className = 'toc-toggle-header';
    // 이미지처럼 'Contents'와 '>' 모양으로 시작
    tocToggle.innerHTML = '<span class="toc-icon-list">☰</span> Contents <span class="toc-arrow">&#9658;</span>'; 
    tocContainer.appendChild(tocToggle);

    // 3-2. 목차 리스트 내용을 담는 컨테이너 생성
    const tocContent = document.createElement('div');
    tocContent.className = 'toc-content-collapsible';
    tocContent.style.display = 'none'; // 초기 닫힘 상태
    tocContainer.appendChild(tocContent);


    // 최상위 리스트 (H2 레벨) 시작
    let tocList = document.createElement('ol'); 
    tocList.className = 'toc-list-level-1';
    tocContent.appendChild(tocList);

    let currentList = tocList; 
    let currentLevel = 2;      

    headings.forEach((heading, index) => {
        const level = parseInt(heading.tagName.substring(1)); 
        
        // 4. 고유 ID 생성 및 할당 (앵커 링크 연결을 위해 필수)
        const headingId = 'toc-heading-' + (index + 1) + '-' + heading.textContent.replace(/[^a-z0-9]/gi, '').substring(0, 10).toLowerCase();
        heading.id = headingId;

        // 5. 계층 구조에 맞게 리스트 조정 (들여쓰기 로직 유지)
        while (currentLevel < level) {
            const newList = document.createElement('ol');
            newList.className = `toc-list-level-${level}`;
            if (currentList.lastChild) {
                currentList.lastChild.appendChild(newList);
            } else {
                currentList.appendChild(document.createElement('li')).appendChild(newList);
            }
            currentList = newList;
            currentLevel++;
        }

        while (currentLevel > level) {
            currentList = currentList.parentNode.closest('ol');
            if (!currentList) {
                currentList = tocList;
                break;
            }
            currentLevel--;
        }

        // 6. 목차 항목 (li) 생성 및 현재 리스트에 추가
        const listItem = document.createElement('li');
        const link = document.createElement('a');
        link.href = '#' + headingId;
        link.textContent = heading.textContent;
        listItem.appendChild(link);
        currentList.appendChild(listItem);
        currentLevel = level; 
    });

    // 8. 💡 수정된 부분: 토글 기능 추가 및 화살표 변경
    tocToggle.addEventListener('click', function() {
        const arrow = tocToggle.querySelector('.toc-arrow');
        if (tocContent.style.display === 'none') {
            tocContent.style.display = 'block';
            arrow.innerHTML = '&#9660;'; // 펼칠 때: ▼ (아래 화살표)
        } else {
            tocContent.style.display = 'none';
            arrow.innerHTML = '&#9658;'; // 닫을 때: ▶ (오른쪽 화살표)
        }
    });

    // 7. 💡 수정된 부분: 목차를 첫 번째 <h2> 태그 위에 삽입
    const firstH2 = postBody.querySelector('h2');
    if (firstH2) {
        postBody.insertBefore(tocContainer, firstH2);
    } else {
        // H2가 없으면 (대안으로) 본문 맨 앞에 삽입
        postBody.insertBefore(tocContainer, postBody.firstChild);
    }
}

// 페이지 로드 후 generateTOC 함수를 실행합니다.
window.onload = function() {
    setTimeout(generateTOC, 500); 
};
//]]>
</script>

🎨 디자인 구현을 위한 CSS 코드 (필수)

이미지와 같은 디자인을 구현하려면 아래 CSS 코드를 테마의 사용자 정의 CSS 영역 (워드프레스의 경우 외모 > 사용자 정의하기 > 추가 CSS) 또는 <head> 태그 내 <style> 태그 안에 삽입해야 합니다.

CSS
/* 1. 전체 목차 컨테이너 스타일 */
#auto-toc-container.toc-box-style {
    border: 1px solid #ddd;
    /* margin: 20px 0; */ /* H2 위에 배치되므로 margin 조정이 필요할 수 있습니다. */
    margin-bottom: 25px; /* 본문과 간격 */
    background-color: #f7f7f7;
    border-radius: 4px;
    font-size: 16px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}

/* 2. 토글 헤더 (Contents) 스타일 - 이미지의 회색 박스 */
.toc-toggle-header {
    background-color: #fcfcfc;
    border-bottom: 1px solid #ddd;
    padding: 12px 15px;
    cursor: pointer;
    font-weight: bold;
    color: #333;
    display: flex; /* 아이콘과 화살표를 정렬 */
    justify-content: space-between; /* 양 끝에 배치 */
    align-items: center;
    border-radius: 4px 4px 0 0;
}

/* 3. 리스트 아이콘 (☰) 스타일 */
.toc-icon-list {
    margin-right: 10px;
    font-size: 1.1em;
    line-height: 1;
}

/* 4. 화살표 스타일 (오른쪽 정렬) */
.toc-arrow {
    font-size: 1.1em;
    font-weight: normal;
    color: #555;
}

/* 5. 목차 내용 (리스트) 스타일 */
.toc-content-collapsible {
    padding: 15px;
}

/* 6. 리스트 항목 스타일 */
.toc-content-collapsible ol {
    padding-left: 20px;
    margin-top: 5px;
    margin-bottom: 5px;
}

/* 7. 계층별 리스트 스타일 */
.toc-list-level-1 {
    /* 최상위 리스트 (H2) */
    list-style-type: decimal; /* 1, 2, 3... */
}

.toc-list-level-2, .toc-list-level-3 {
    /* 하위 리스트 (H3, H4) */
    list-style-type: disc; /* •, o, ■ 등 */
    margin-left: 15px;
}

.toc-content-collapsible a {
    text-decoration: none;
    color: #0073aa; /* 링크 색상 */
}
 

🎨전체코드::

  
<!-- 
============================================================
Blogger 자동 목차 생성 위젯 (Automatic Table of Contents Widget)
============================================================
[사용 방법]
1. 이 전체 코드를 복사합니다.
2. Blogger 대시보드에서 [테마] -> [HTML 편집]으로 이동합니다.
3. </body> 닫는 태그 바로 위에 이 코드를 붙여넣습니다.
4. (선택 사항) 사용 중인 테마에 따라 '.post-body' 선택자가 다를 수 있습니다.
   만약 목차가 생성되지 않으면 JavaScript 코드 내의 'postBody' 변수 설정을
   게시물 본문 영역의 정확한 CSS 선택자로 변경해야 합니다.
-->
<style>
/* ============================================================
목차 위젯 기본 스타일 (Custom Styles)
============================================================
/* 1. 전체 목차 컨테이너 스타일 */
#auto-toc-container.toc-box-style {
    border: 1px solid #ddd;
    /* margin: 20px 0; */ /* H2 위에 배치되므로 margin 조정이 필요할 수 있습니다. */
    margin-bottom: 25px; /* 본문과 간격 */
    background-color: #f7f7f7;
    border-radius: 4px;
    font-size: 16px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}

/* 2. 토글 헤더 (Contents) 스타일 - 이미지의 회색 박스 */
.toc-toggle-header {
    background-color: #fcfcfc;
    border-bottom: 1px solid #ddd;
    padding: 12px 15px;
    cursor: pointer;
    font-weight: bold;
    color: #333;
    display: flex; /* 아이콘과 화살표를 정렬 */
    justify-content: space-between; /* 양 끝에 배치 */
    align-items: center;
    border-radius: 4px 4px 0 0;
}

/* 3. 리스트 아이콘 (&#9776;) 스타일 */
.toc-icon-list {
    margin-right: 10px;
    font-size: 1.1em;
    line-height: 1;
}

/* 4. 화살표 스타일 (오른쪽 정렬) */
.toc-arrow {
    font-size: 1.1em;
    font-weight: normal;
    color: #555;
}

/* 5. 목차 내용 (리스트) 스타일 */
.toc-content-collapsible {
    padding: 15px;
}

/* 6. 리스트 항목 스타일 */
.toc-content-collapsible ol {
    padding-left: 20px;
    margin-top: 5px;
    margin-bottom: 5px;
}

/* 7. 계층별 리스트 스타일 */
.toc-list-level-1 {
    /* 최상위 리스트 (H2) */
    list-style-type: decimal; /* 1, 2, 3... */
}

.toc-list-level-2, .toc-list-level-3 {
    /* 하위 리스트 (H3, H4) */
    list-style-type: disc; /* &#8226;, o, &#9632; 등 */
    margin-left: 15px;
}

.toc-content-collapsible a {
    text-decoration: none;
    color: #0073aa; /* 링크 색상 */
}
</style>

<script>
//<![CDATA[
// JavaScript를 이용한 자동 목차 생성 로직
function generateTOC() {
    // 1. 블로그 게시물 본문 요소를 찾습니다.
    const postBody = document.querySelector('.post-body') || document.querySelector('.entry-content') || document.querySelector('.post-content');

    // 게시물 본문을 찾지 못하거나 목차 생성 제외 태그가 발견되면 종료
    if (!postBody) return;
    if (postBody.querySelector('.no-toc')) return;


    // 2. H2, H3, H4 태그를 모두 찾습니다. (H1은 게시물 제목이므로 제외)
    const headings = postBody.querySelectorAll('h2, h3, h4');
    if (headings.length < 2) return; // 최소 두 개 이상의 제목이 있어야 목차를 생성합니다.

    // 3. 목차(TOC) 컨테이너 및 토글 영역 생성 (이미지 모양 반영)
    const tocContainer = document.createElement('div');
    tocContainer.id = 'auto-toc-container';
    tocContainer.className = 'toc-box-style'; // CSS 적용을 위한 클래스

    // 3-1. 토글 헤더 영역 (Contents + Arrow) 생성
    const tocToggle = document.createElement('div');
    tocToggle.className = 'toc-toggle-header';
    // 이미지처럼 'Contents'와 '>' 모양으로 시작
    tocToggle.innerHTML = '<span class="toc-icon-list">☰</span> Contents <span class="toc-arrow">&#9658;</span>'; 
    tocContainer.appendChild(tocToggle);

    // 3-2. 목차 리스트 내용을 담는 컨테이너 생성
    const tocContent = document.createElement('div');
    tocContent.className = 'toc-content-collapsible';
    tocContent.style.display = 'none'; // 초기 닫힘 상태
    tocContainer.appendChild(tocContent);


    // 최상위 리스트 (H2 레벨) 시작
    let tocList = document.createElement('ol'); 
    tocList.className = 'toc-list-level-1';
    tocContent.appendChild(tocList);

    let currentList = tocList; 
    let currentLevel = 2;      

    headings.forEach((heading, index) => {
        const level = parseInt(heading.tagName.substring(1)); 
        
        // 4. 고유 ID 생성 및 할당 (앵커 링크 연결을 위해 필수)
        const headingId = 'toc-heading-' + (index + 1) + '-' + heading.textContent.replace(/[^a-z0-9]/gi, '').substring(0, 10).toLowerCase();
        heading.id = headingId;

        // 5. 계층 구조에 맞게 리스트 조정 (들여쓰기 로직 유지)
        while (currentLevel < level) {
            const newList = document.createElement('ol');
            newList.className = `toc-list-level-${level}`;
            if (currentList.lastChild) {
                currentList.lastChild.appendChild(newList);
            } else {
                currentList.appendChild(document.createElement('li')).appendChild(newList);
            }
            currentList = newList;
            currentLevel++;
        }

        while (currentLevel > level) {
            currentList = currentList.parentNode.closest('ol');
            if (!currentList) {
                currentList = tocList;
                break;
            }
            currentLevel--;
        }

        // 6. 목차 항목 (li) 생성 및 현재 리스트에 추가
        const listItem = document.createElement('li');
        const link = document.createElement('a');
        link.href = '#' + headingId;
        link.textContent = heading.textContent;
        listItem.appendChild(link);
        currentList.appendChild(listItem);
        currentLevel = level; 
    });

    // 8. 💡 수정된 부분: 토글 기능 추가 및 화살표 변경
    tocToggle.addEventListener('click', function() {
        const arrow = tocToggle.querySelector('.toc-arrow');
        if (tocContent.style.display === 'none') {
            tocContent.style.display = 'block';
            arrow.innerHTML = '&#9660;'; // 펼칠 때: ▼ (아래 화살표)
        } else {
            tocContent.style.display = 'none';
            arrow.innerHTML = '&#9658;'; // 닫을 때: ▶ (오른쪽 화살표)
        }
    });

    // 7. 💡 수정된 부분: 목차를 첫 번째 <h2> 태그 위에 삽입
    const firstH2 = postBody.querySelector('h2');
    if (firstH2) {
        postBody.insertBefore(tocContainer, firstH2);
    } else {
        // H2가 없으면 (대안으로) 본문 맨 앞에 삽입
        postBody.insertBefore(tocContainer, postBody.firstChild);
    }
}

// 페이지 로드 후 generateTOC 함수를 실행합니다.
window.onload = function() {
    setTimeout(generateTOC, 500); 
};
//]]>
</script>  

</body>의 바로 위에 복사해서 넣기



댓글 쓰기

0 댓글