Wagtail 教程系列 記錄了基于 Wagtail 搭建博客站點的整個過程参淫,博客站點 所呈現(xiàn)的即是搭建過程的最新效果拙绊。
更多 Wagtail 內(nèi)容:https://slowread.cn/wagtail-tutorials
自動生成文章右側(cè)TOC導航
此部分屬于通用內(nèi)容,非 Wagtail
必需內(nèi)容荡短,是為了完善/優(yōu)化基于 Wagtail
搭建的博客。
說明
- 需要在文章頁面中創(chuàng)建一對 DIV 標簽订雾,涵蓋范圍為需要自動生成TOC導航的文章內(nèi)容部分肢预,ID 為 JS 腳本中設定的名字 sowread_post_body。
- JS 腳本自動查找第一個標題級別洼哎,只顯示兩級目錄烫映。
CSS
/* TOC 導航 */
#TOCbar{
text-align:left; position:fixed; width: auto; color:#2F7CFF;
height: auto; top:4em; right:0; margin: 0.25em /*離頁面頂部與右側(cè)的距離*/
}
#TOCbarTab{
float:left; width: 2.5em; border:1px solid #e5e5e5; border-right:none;
text-align:center; background:#ffffff;
}
#TOCbarContents{
float:left; overflow:auto; overflow-x:hidden; padding: 0.5em; color:#2F7CFF;
width:18em; min-height:6em; max-height:50em;
border:1px solid #e5e5e5; border-right:none; background:#ffffff;
}
#TOCbarContents dl{ margin:0; padding:0; }
#TOCbarContents dt{ margin-left: 0;}
#TOCbarContents dd{ padding-left: 1.5em; margin-bottom: 0;}
#TOCbarContents dd, dt { cursor: pointer; }
#TOCbarContents dd:hover, dt:hover { color:#ffffff;background:#2F7CFF;}
/* TOC 導航 */
JavaScript
// 自動生成 TOC 導航
var BlogDirectory = {
/*
獲取元素位置,距瀏覽器左邊界的距離(left)和距瀏覽器上邊界的距離(top)
*/
getElementPosition:function (ele) {
var topPosition = 0;
var leftPosition = 0;
while (ele){
topPosition += ele.offsetTop;
leftPosition += ele.offsetLeft;
ele = ele.offsetParent;
}
return {top:topPosition, left:leftPosition};
},
/*
獲取滾動條當前位置
*/
getScrollBarPosition:function () {
var scrollBarPosition = document.body.scrollTop || document.documentElement.scrollTop;
return scrollBarPosition;
},
/*
移動滾動條噩峦,finalPos 為目的位置锭沟,internal 為移動速度
*/
moveScrollBar:function(finalpos, interval) {
// 若不支持此方法,則退出
if(!window.scrollTo) {
return false;
}
// 窗體滾動時识补,禁用鼠標滾輪
window.onmousewheel = function(){
return false;
};
// 清除計時
if (document.body.movement) {
clearTimeout(document.body.movement);
}
var currentpos =BlogDirectory.getScrollBarPosition(); // 獲取滾動條當前位置
var dist = 0;
if (currentpos == finalpos) { // 到達預定位置族淮,則解禁鼠標滾輪,并退出
window.onmousewheel = function(){
return true;
};
return true;
}
if (currentpos < finalpos) { // 未到達凭涂,則計算下一步所要移動的距離
dist = Math.ceil((finalpos - currentpos)/10);
currentpos += dist;
}
if (currentpos > finalpos) {
dist = Math.ceil((currentpos - finalpos)/10);
currentpos -= dist;
}
var scrTop = BlogDirectory.getScrollBarPosition(); // 獲取滾動條當前位置
window.scrollTo(0, currentpos); // 移動窗口
if(BlogDirectory.getScrollBarPosition() == scrTop) // 若已到底部祝辣,則解禁鼠標滾輪,并退出
{
window.onmousewheel = function(){
return true;
};
return true;
}
// 進行下一步移動
var repeat = "BlogDirectory.moveScrollBar(" + finalpos + "," + interval + ")";
document.body.movement = setTimeout(repeat, interval);
},
htmlDecode:function (text){
var temp = document.createElement("div");
temp.innerHTML = text;
var output = temp.innerText || temp.textContent;
temp = null;
return output;
},
/*
創(chuàng)建博客目錄切油,id表示包含博文正文的 div 容器的 id蝙斜,mt 和 st 分別表示主標題和次級標題的標簽名稱,interval 表示移動的速度
*/
createBlogDirectory:function (id, mt, st, interval){
// 獲取博文正文div容器
var elem = document.getElementById(id);
if(!elem) return false;
// 獲取div中所有元素結(jié)點
var nodes = elem.getElementsByTagName("*");
// 創(chuàng)建博客目錄的div容器
var divTOCbar = document.createElement('DIV');
divTOCbar.className = 'TOCbar';
divTOCbar.setAttribute('id', 'TOCbar');
var divTOCbarTab = document.createElement('DIV');
divTOCbarTab.setAttribute('id', 'TOCbarTab');
divTOCbar.appendChild(divTOCbarTab);
var h3 = document.createElement('h4');
divTOCbarTab.appendChild(h3);
var txt = document.createTextNode('<'); // 目錄導航名字
h3.appendChild(txt);
var divTOCbarContents = document.createElement('DIV');
divTOCbarContents.style.display = 'none';
divTOCbarContents.setAttribute('id', 'TOCbarContents');
divTOCbar.appendChild(divTOCbarContents);
// 創(chuàng)建自定義列表
var dlist = document.createElement("dl");
divTOCbarContents.appendChild(dlist);
var num = 0; // 統(tǒng)計找到的mt和st
// mt = mt.toUpperCase(); // 轉(zhuǎn)化成大寫
// st = st.toUpperCase(); // 轉(zhuǎn)化成大寫
mt = "H1";
st = "H2";
var hhArray = ["H1","H2","H3","H4","H5","H6"];
// 查找第一個 標題 級別澎胡,如果找到 自動設置下一級標題
for(var x=0; x<nodes.length; x++)
{
if ($.inArray(nodes[x].nodeName,hhArray) != -1)
{
mt = hhArray[$.inArray(nodes[x].nodeName,hhArray)];
if ($.inArray(nodes[x].nodeName,hhArray) <= 4)
{
st = hhArray[$.inArray(nodes[x].nodeName,hhArray) + 1];
}
break;
}
}
// 遍歷所有元素結(jié)點
for(var i=0; i<nodes.length; i++)
{
if(nodes[i].nodeName == mt|| nodes[i].nodeName == st)
{
// 獲取標題文本
var nodetext = nodes[i].innerHTML.replace(/<\/?[^>]+>/g,""); // innerHTML里面的內(nèi)容可能有HTML標簽孕荠,所以用正則表達式去除HTML的標簽
nodetext = nodetext.replace(/ /ig, ""); // 替換掉所有的
nodetext = BlogDirectory.htmlDecode(nodetext);
// 插入錨
nodes[i].setAttribute("id", "blogTitle" + num);
var item;
switch(nodes[i].nodeName)
{
case mt: // 若為主標題
item = document.createElement("dt");
break;
case st: // 若為子標題
item = document.createElement("dd");
break;
}
// 創(chuàng)建錨鏈接
var itemtext = document.createTextNode(nodetext);
item.appendChild(itemtext);
item.setAttribute("name", num);
item.onclick = function(){ // 添加鼠標點擊觸發(fā)函數(shù)
var pos = BlogDirectory.getElementPosition(document.getElementById("blogTitle" + this.getAttribute("name")));
if(!BlogDirectory.moveScrollBar(pos.top, interval)) return false;
};
// 將自定義表項加入自定義列表中
dlist.appendChild(item);
num++;
}
}
if(num == 0) return false;
/* 鼠標進入時的事件處理 */
divTOCbarTab.onmouseenter = function(){
divTOCbarContents.style.display = 'block';
};
/* 鼠標離開時的事件處理 */
divTOCbar.onmouseleave = function() {
divTOCbarContents.style.display = 'none';
};
document.body.appendChild(divTOCbar);
}
};
window.onload=function(){
/* 頁面加載完成之后生成博客目錄 */
// h2,h3 非必須指定,程序內(nèi)部自動查找第一個標題級別 2018-12-21
BlogDirectory.createBlogDirectory("sowread_post_body","h2","h3",20);
};
// 自動生成 TOC 導航