Tạo mục lục tự động -Table of content trong bài viết cho blogspot

Hướng dẫn cài đặt mục lục cho blogspot - Khi khách truy cập web/blog thì 95% người đọc sẽ tìm đến phần Mục lục (Table of Content) để xem trước và định hình cấu trúc bài viết. Đối với blog bạn cũng thường thấy mục lục ở những bài có nội dung dài và được chia ra làm nhiều mục lớn nhỏ.

“ Bảng mục lục” hay còn được gọi là “ Table of contents ” là phần rất quan trọng vì nó là điểm thể hiện tính chuyên nghiệp của người viết đối với bất kì một loại văn bản nào. Việc phân chia thành các mục lớn mục nhỏ và cho biết chính xác vị trí của nó trong văn bản giúp cho bài viết được rõ ràng và người đọc sẽ nắm được nội dung khái quát dù chỉ mới nhìn lướt qua văn bản đó.
Với những bài viết dài, phân chia nội dung theo chủ đề, tác giả sẽ thường xây dựng một mục lục để liên kết nội dung con giúp người đọc nhanh chóng chuyển đến nơi, chương bài mình muốn. Vậy họ đã làm điều đó như thế nào?

Với blogspot thì việc này cần phải làm theo cách thủ công với việc trong khi viết bài cần phân chia các mục thông qua các thẻ h2 h3 h4 h5 h6 (nôm na là cha con cháu chắt chút...)

Hướng dẫn cài đặt mục lục theo cách thủ công

Với cách thủ công ta chỉ sử dụng cho bài nào cần mục lục và phần mục lục ta có thể chọn vị trí phù hợp, không như cách tự động tuy không sử dụng nó luôn có phần button ngay đầu bài viết.

Bước 1: Thêm css

Thêm css cho blog bằng cách dán đoạn css sau vào trước ]]></b:skin> hoặc </style> tùy theo template
/* Post toc css */
.posttoc{border:1px solid #ddd;line-height:1.4em;margin:30px auto;padding:20px 30px 20px 10px;display:block;width:70%;}
.posttoc button{background:transparent; font-size:22px;position:relative; outline:none;border:none; padding:0 0 0 15px;}
.posttoc button a {padding:0px 2px;cursor:pointer;} 
.posttoc button a:hover{ text-decoration:underline; } 
.posttoc button span {font-size:15px; margin:0px 10px; }
.posttoc li{margin:10px 0;  } 
.posttoc li a {text-decoration:none; font-size:18px; text-transform:capitalize;} 
.posttoc li a:hover {text-decoration: underline;}
.posttoc li li {margin:4px 0px;} 
.posttoc li li a{font-size:15px;}
.posttoc ol{counter-reset:section1;list-style:none}
.posttoc ol ol{counter-reset:section2}
.posttoc ol ol ol{counter-reset:section3}
.posttoc ol ol ol ol{counter-reset:section4}
.posttoc ol ol ol ol ol{counter-reset:section5}
.posttoc li:before{content:counter(section1);counter-increment:section1;position:relative;padding:0 8px 0 0;font-size:18px}
.posttoc li li:before{content:counter(section1) "." counter(section2);counter-increment:section2;font-size:14px}
.posttoc li li li:before{content:counter(section1) "."counter(section2) "." counter(section3);counter-increment:section3}
.posttoc li li li li:before{content:counter(section1) "."counter(section2) "."counter(section3) "." counter(section4);counter-increment:section4}
.posttoc li li li li li:before{content:counter(section1) "."counter(section2) "."counter(section3) "." counter(section4)"." counter(section5);counter-increment:section5}

Bước 2: Thêm javascript

Dán đoạn javascript sau vào trước </head>
<script> 
//<![CDATA[ 
function POSTTOC(){var a=1,b=0,c="";document.getElementById("post-toc").innerHTML=document.getElementById("post-toc").innerHTML.replace(/<h([\d]).*?>(.*?)<\/h([\d]).*?>/gi,function(d,e,f,g){return e!=g?d:(e>a?c+=new Array(e-a+1).join("<ol class='point"+a+"'>"):e<a&&(c+=new Array(a-e+1).join("</ol></li>")),b+=1,c+='<li><a href="#point'+b+'">'+f+"</a>",a=parseInt(e),"<h"+e+" id='point"+b+"'>"+f+"</h"+g+">")}),a&&(c+=new Array(a+1).join("</ol>")),document.getElementById("POSTTOC").innerHTML+=c}function Toggletoc(){var a=document.getElementById("POSTTOC"),b=document.getElementById("Tog");"none"===a.style.display?(a.style.display="block",b.innerHTML="Hide"):(a.style.display="none",b.innerHTML="Show")} 
//]]> 
</script>

Bước 3: Sửa <data:post.body/>

Tìm thẻ <data:post.body/> và sửa nó thành
<div id='post-toc'><data:post.body/></div>

Bước 4: Khi viết bài

Thêm code vào bài viết
Khi viết đặt code sau vào ngay đầu bài viết hoặc sau vài dòng cũng được
<div class="posttoc"> 
<button>Mục lục <span>[<a onclick="Toggletoc()"  id="Tog">Hide</a>]</span></button> 
<div id="POSTTOC"></div> 
</div>
Việc sau cùng là dán code sau vào cuối bài viết để gọi javascript
<script>POSTTOC();</script>
Trong quá trình viết bài
Ví dụ một cấu trúc như sau:
Bài viết có 3 mục lớn coi như là mục cha, mỗi tiêu đề mục này sẽ bao bao bằng thẻ h2. Trong mỗi mục lớn ví dụ có 2 mục con, mỗi tiêu đề mục con bao bằng thẻ h3. Trong mỗi mục con có 2 mục cháu, mỗi tiêu đề mục cháu bao bằng thẻ h4. Nếu có chắt thì bao bằng thẻ h5....Chỉ tới h6 thôi nhé(chút).
Ví dụ cho một mục cha.
<h2>Mục cha 1</h2>
<h3>Mục con</h3>
<h4>Mục cháu</h4>
Nội dung
<h4>Mục cháu</h4>
Nội dung
<h3>Mục con</h3>
<h4>Mục cháu</h4>
Nội dung
<h4>Mục cháu</h4>
Nội dung

Hướng dẫn cài đặt mục lục tự động

Theo cách này các bước 1 và 2 vẫn làm như hướng dẫn ở trên và khi viết bài không cần thêm code vào bài viết và viết luôn theo hướng dẫn "Trong khi viết bài ở trên" và chỉ có khác một chút là khi sửa code <data:post.body/> ở bước 3 bên trên ta làm như sau:
Thay <data:post.body/> thành
<div id='post-toc'>
<div class='posttoc'> 
<button>Mục lục <span>[<a id='Tog' onclick='Toggletoc()'>Hide</a>]</span></button> 
<div id='POSTTOC'/> 
</div>
<data:post.body/>
<script>POSTTOC();</script>
</div>

Cài đặt mục lục ngay tại bài viết không cần chỉnh sửa mẫu

Với cách cài đặt mục lục theo cách này ta không cần can thiệp vào mẫu mà toàn bộ code để ngay trong bài viết, nó phù hợp với blog chỉ có nhu cầu một số bài cần sử dụng mục lục và không muốn trong mẫu quá nhiều CSS cùng Javascript làm nặng blog.
Khi viết bài ta sử dụng code theo như bên dưới:
<div id='post-toc'>

<!-- Vài dòng giới thiệu -->

<div class="posttoc"> 
<button>Mục lục <span>[<a onclick="Toggletoc()"  id="Tog">Hide</a>]</span></button> 
<div id="POSTTOC"></div> 
</div>

<!-- Nội dung bài viết -->

<script>POSTTOC();</script>
</div>
<style>
  .posttoc{border:1px solid #ddd;line-height:1.4em;margin:30px auto;padding:20px 30px 20px 10px;display:block;width:70%;}
.posttoc button{background:transparent; font-size:22px;position:relative; outline:none;border:none; padding:0 0 0 15px;}
.posttoc button a {padding:0px 2px;cursor:pointer;} 
.posttoc button a:hover{ text-decoration:underline; } 
.posttoc button span {font-size:15px; margin:0px 10px; }
.posttoc li{margin:10px 0;  } 
.posttoc li a {text-decoration:none; font-size:18px; text-transform:capitalize;} 
.posttoc li a:hover {text-decoration: underline;}
.posttoc li li {margin:4px 0px;} 
.posttoc li li a{font-size:15px;}
.posttoc ol{counter-reset:section1;list-style:none}
.posttoc ol ol{counter-reset:section2}
.posttoc ol ol ol{counter-reset:section3}
.posttoc ol ol ol ol{counter-reset:section4}
.posttoc ol ol ol ol ol{counter-reset:section5}
.posttoc li:before{content:counter(section1);counter-increment:section1;position:relative;padding:0 8px 0 0;font-size:18px}
.posttoc li li:before{content:counter(section1) "." counter(section2);counter-increment:section2;font-size:14px}
.posttoc li li li:before{content:counter(section1) "."counter(section2) "." counter(section3);counter-increment:section3}
.posttoc li li li li:before{content:counter(section1) "."counter(section2) "."counter(section3) "." counter(section4);counter-increment:section4}
.posttoc li li li li li:before{content:counter(section1) "."counter(section2) "."counter(section3) "." counter(section4)"." counter(section5);counter-increment:section5}
</style>
<script> 
//<![CDATA[ 
function POSTTOC() {
    var a = 1,
        b = 0,
        c = "";
    document.getElementById("post-toc").innerHTML = document.getElementById("post-toc").innerHTML.replace(/<h([\d]).*?>(.*?)<\/h([\d]).*?>/gi, function(d, e, f, g) {
        return e != g ? d : (e > a ? c += new Array(e - a + 1).join("<ol class='point" + a + "'>") : e < a && (c += new Array(a - e + 1).join("</ol></li>")), b += 1, c += '<li><a href="#point' + b + '">' + f + "</a>", a = parseInt(e), "<h" + e + " id='point" + b + "'>" + f + "</h" + g + ">")
    }), a && (c += new Array(a + 1).join("</ol>")), document.getElementById("POSTTOC").innerHTML += c
}

function Toggletoc() {
    var a = document.getElementById("POSTTOC"),
        b = document.getElementById("Tog");
    "none" === a.style.display ? (a.style.display = "block", b.innerHTML = "Hide") : (a.style.display = "none", b.innerHTML = "Show")
}
  POSTTOC();
//]]> 
</script>

Tạo mục lục tự động - Table of content kiểu template Median UI

CSS
.post .tocInner,.post .spoiler{border:1px solid #fefefe;border-left:0;border-right:0;padding:15px 15px;margin:30px 0;font-size:14px}
.post .tocTitle,.post .spoilerTitle{outline:0;font-weight:700;line-height:1.8em;display:flex;align-items:center}
.post .tocTitle:after{content:'Hide all';font-weight:400;font-size:85%;font-family:sans-serif;margin-left:auto}
.post .tocContent,.post .spoilerContent{max-height:1000vh;transition:all .4s ease;overflow:hidden}
.post .tocInput:checked ~ .tocContent{max-height:0}
.post .tocInput:checked ~ .tocTitle:after{content:'Show all'}
.post .tocInner a{display:flex;color:inherit}
.post .tocInner ol,.post .tocInner ul,.tableOfContent ol{padding:0;list-style:none;font-size:inherit;font-weight:400;counter-reset:toc-count;line-height:1.75em}
.post .tocInner li,.tableOfContent li{display:flex;flex-wrap:wrap}
.post .tocInner li ol,.post .tocInner li ul,.tableOfContent li ol{width:100%;padding-left:26px;margin-bottom:10px;margin-top:5px}
.post .tocInner li > *:before,.tableOfContent li > a:before{content:counters(toc-count,'.')'. ';counter-increment:toc-count;display:inline-block;min-width:20px;margin-right:5px;flex-shrink:0;font-weight:400}
.postToc{position:fixed;background-color:#f7faff;top:0;right:-355px;bottom:0;left:0;width:355px;margin-left:auto;transition:all .4s ease;display:flex;align-items:center;justify-content:flex-end;z-index:2}
.tableOfContainer{width:100%;height:100%;transition:all .1s ease;display:flex;position:relative;z-index:3}
.tableOfHeader{display:flex;align-items:center;justify-content:space-between;padding:15px 20px 15px 30px;background-color:#f7faff;font-size:15px;font-weight:400;position:absolute;top:70px;right:0;left:0;z-index:1;transition:all .4s ease}
.tableOfHeader svg{width:20px;height:20px}
.tableOfHeader span:before{content:attr(data-text)}
.tableOfIcon{width:55px;height:40px;display:flex;align-items:center;justify-content:center;background-color:#fefefe;border-radius:.3em 0 0 .3em;border:1px solid #fefefe;border-right:0;box-shadow:0 10px 20px 0 rgb(30 30 30 / 8%);position:absolute;top:10px;left:-55px}
.tableOfIcon:before{content:'';display:block;width:12px;height:12px;background-color:#204ecf;border:2px solid #fefefe;border-radius:50%;position:absolute;top:8px;left:15px;webkit-animation:indicator 1s ease infinite;-moz-animation:indicator 1s ease infinite;animation:indicator 1s ease infinite}
.tableOfInner{margin-top:70px;padding:50px 25px 50px 30px;width:100%;overflow-y:auto}
.tableOfContent a{line-height:1.8em;margin-bottom:4px;color:inherit;display:flex}
.tableOfContent ol{margin:0}
.tableOfContent li > a:before{opacity:.7}
.tocMenu:checked ~ .postToc{right:0}
.tocMenu:checked ~ .postToc .tableOfIcon{opacity:0;visibility:hidden}
.fullClose{display:block;position:fixed;top:0;left:0;right:0;bottom:0;z-index:2;-webkit-transition:all .1s ease;transition:all .1s ease;background:transparent;opacity:0;visibility:hidden}
.darkMode .tableOfContainer,.darkMode .tableOfHeader{background-color:#1e1e1e}
.darkMode .tableOfIcon{background-color:#2d2d30;border-color:transparent}
.darkMode .tableOfIcon:before{border-color:#2d2d30}
.darkMode .tocInner .tocTitle:after{color:#989b9f}
.darkMode .tableOfContent a, .darkMode .post .tocInner a{color:#fefefe}
@media screen and (max-width:896px){.postToc{right:0;width:75%;max-width:480px;margin-right:-480px}
.tableOfContainer{border-radius:15px 0 0 15px}
.tableOfHeader,.tableOfIcon{top:40px}
.tableOfInner{margin-top:40px}
.tocMenu:checked ~ .postToc{z-index:10;margin-right:0}
.tocMenu:checked ~ .postToc .fullClose{background:rgba(0,0,0,.25);opacity:1;visibility:visible}
.darkMode .tableOfContainer,.darkMode .tableOfHeader{background-color:#252526}
}
@media screen and (max-width:480px){.postToc{margin-right:-75%}
.tableOfHeader,.tableOfInner{padding-left:20px;padding-right:20px}
}
Javascript
<b:if cond='!data:view.isError and data:view.isPost'>
    <script>/*<![CDATA[*/ /* Table of Content, Credit: blustemy.io/creating-a-table-of-contents-in-javascript */
class TableOfContents { constructor({ from, to }) { this.fromElement = from; this.toElement = to; this.headingElements = this.fromElement.querySelectorAll("h1, h2, h3, h4, h5, h6"); this.tocElement = document.createElement("div"); }; getMostImportantHeadingLevel() { let mostImportantHeadingLevel = 6; for (let i = 0; i < this.headingElements.length; i++) { let headingLevel = TableOfContents.getHeadingLevel(this.headingElements[i]); mostImportantHeadingLevel = (headingLevel < mostImportantHeadingLevel) ? headingLevel : mostImportantHeadingLevel; } return mostImportantHeadingLevel; }; static generateId(headingElement) { return headingElement.textContent.replace(/\s+/g, "_"); }; static getHeadingLevel(headingElement) { switch (headingElement.tagName.toLowerCase()) { case "h1": return 1; case "h2": return 2; case "h3": return 3; case "h4": return 4; case "h5": return 5; case "h6": return 6; default: return 1; } }; generateToc() { let currentLevel = this.getMostImportantHeadingLevel() - 1, currentElement = this.tocElement; for (let i = 0; i < this.headingElements.length; i++) { let headingElement = this.headingElements[i], headingLevel = TableOfContents.getHeadingLevel(headingElement), headingLevelDifference = headingLevel - currentLevel, linkElement = document.createElement("a"); if (!headingElement.id) { headingElement.id = TableOfContents.generateId(headingElement); } linkElement.href = `#${headingElement.id}`; linkElement.textContent = headingElement.textContent; if (headingLevelDifference > 0) { for (let j = 0; j < headingLevelDifference; j++) { let listElement = document.createElement("ol"), listItemElement = document.createElement("li"); listElement.appendChild(listItemElement); currentElement.appendChild(listElement); currentElement = listItemElement; } currentElement.appendChild(linkElement); } else { for (let j = 0; j < -headingLevelDifference; j++) { currentElement = currentElement.parentNode.parentNode; } let listItemElement = document.createElement("li"); listItemElement.appendChild(linkElement); currentElement.parentNode.appendChild(listItemElement); currentElement = listItemElement; } currentLevel = headingLevel; } this.toElement.appendChild(this.tocElement.firstChild); } } /*]]>*/</script>
  </b:if>
HTML
Cài đặt trong <b:defaultmarkup type='Common'>
<b:includable id='postTableofContent'>
        <input class='tocMenu hidden' id='offtoc-menu' type='checkbox'/>
<div class='postToc'>
<div class='tableOfContainer'>
<label class='tableOfHeader' for='offtoc-menu'>
<span class='tableOfIcon'>
<svg class='line' viewBox='0 0 24 24'><g transform='translate(3.610000, 2.750100)'><line x1='11.9858' x2='4.7658' y1='12.9463' y2='12.9463'/><line x1='11.9858' x2='4.7658' y1='9.1865' y2='9.1865'/><line x1='7.521' x2='4.766' y1='5.4272' y2='5.4272'/><path d='M7.63833441e-14,9.25 C7.63833441e-14,16.187 2.098,18.5 8.391,18.5 C14.685,18.5 16.782,16.187 16.782,9.25 C16.782,2.313 14.685,0 8.391,0 C2.098,0 7.63833441e-14,2.313 7.63833441e-14,9.25 Z'/></g></svg>
</span>
<span data-text='Table of contents'/>
<svg class='line' viewBox='0 0 24 24'><g transform='translate(12.000000, 12.000000) rotate(-90.000000) translate(-12.000000, -12.000000) translate(5.000000, 8.500000)'><path d='M14,0 C14,0 9.856,7 7,7 C4.145,7 0,0 0,0'/></g></svg>
</label>
<div class='tableOfInner'>
<div class='tableOfContent' id='tocContent'/>
</div>
<script>/*<![CDATA[*/ document.addEventListener('DOMContentLoaded', () => new TableOfContents({from: document.querySelector('#postBody'), to: document.querySelector('#tocContent')}).generateToc() ); /*]]>*/</script>
</div>
</div>
<label class='fullClose' for='offtoc-menu'/>
      </b:includable>
Thẻ gọi để mục lục xuất hiện ở cạnh bên
Dán thẻ này trong phần Post footer là khu vực giữa thẻ </article> và </b:includable>
<!--[ Post table of content ]-->
<b:include cond='data:view.isPost and !data:view.isPreview and data:post.labels none (label =&gt; label.name in [&quot;Product&quot; , &quot;Label_1&quot;])' data='post' name='postTableofContent'/>
Theo:mybloggertricks
Publis: 

Post a Comment

🙂😬😀😂🤣😍💖
Windows + . hoặc Windows + ; để chèn emoji