Wagtail 教程 4:自動生成文章右側(cè)TOC導航

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(/&nbsp;/ig, ""); // 替換掉所有的 &nbsp;
              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 導航
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末攻谁,一起剝皮案震驚了整個濱河市稚伍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌戚宦,老刑警劉巖个曙,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異阁苞,居然都是意外死亡困檩,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門那槽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悼沿,“玉大人,你說我怎么就攤上這事骚灸≡阒海” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長义郑。 經(jīng)常有香客問我蝶柿,道長,這世上最難降的妖魔是什么非驮? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任交汤,我火速辦了婚禮,結(jié)果婚禮上劫笙,老公的妹妹穿的比我還像新娘芙扎。我一直安慰自己,他們只是感情好填大,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布戒洼。 她就那樣靜靜地躺著,像睡著了一般允华。 火紅的嫁衣襯著肌膚如雪圈浇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天靴寂,我揣著相機與錄音磷蜀,去河邊找鬼。 笑死百炬,一個胖子當著我的面吹牛蠕搜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播收壕,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼轨蛤!你這毒婦竟也來了蜜宪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤祥山,失蹤者是張志新(化名)和其女友劉穎圃验,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缝呕,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡澳窑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了供常。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摊聋。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖栈暇,靈堂內(nèi)的尸體忽然破棺而出麻裁,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布煎源,位于F島的核電站色迂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏手销。R本人自食惡果不足惜歇僧,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锋拖。 院中可真熱鬧诈悍,春花似錦、人聲如沸姑隅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讲仰。三九已至慕趴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鄙陡,已是汗流浹背冕房。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留趁矾,地道東北人耙册。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像毫捣,于是被迫代替她去往敵國和親详拙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容